1 /*****************************************************************************
2 * vcd.c : VCD input module for vlc
3 * using libcdio, libvcd and libvcdinfo. vlc-specific things tend
5 *****************************************************************************
6 * Copyright (C) 2000, 2003, 2004 VideoLAN
9 * Authors: Rocky Bernstein <rocky@panix.com>
10 * Johan Bilien <jobi@via.ecp.fr>
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
25 *****************************************************************************/
27 /*****************************************************************************
29 *****************************************************************************/
32 #include <vlc/input.h>
35 #include "../../demux/mpeg/system.h"
37 #include "vcdplayer.h"
40 #include <cdio/cdio.h>
41 #include <cdio/cd_types.h>
42 #include <cdio/logging.h>
43 #include <cdio/util.h>
44 #include <libvcd/info.h>
45 #include <libvcd/logging.h>
49 /* how many blocks VCDRead will read in each loop */
50 #define VCD_BLOCKS_ONCE 20
51 #define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE)
53 #define VCD_MRL_PREFIX "vcdx://"
55 /*****************************************************************************
57 *****************************************************************************/
59 /* First those which are accessed from outside (via pointers). */
60 static int VCDRead ( input_thread_t *, byte_t *, size_t );
61 static int VCDSetProgram ( input_thread_t *, pgrm_descriptor_t * );
63 /* Now those which are strictly internal */
64 static void VCDSetOrigin ( input_thread_t *, lsn_t origin_lsn,
65 lsn_t cur_lsn, lsn_t end_lsn,
66 int cur_entry, track_t track );
67 static int VCDEntryPoints ( input_thread_t * );
68 static int VCDLIDs ( input_thread_t * );
69 static int VCDSegments ( input_thread_t * );
70 static void VCDTracks ( input_thread_t * );
71 static int VCDReadSector ( vlc_object_t *p_this,
72 const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn,
74 static char *VCDParse ( input_thread_t *,
75 /*out*/ vcdinfo_itemid_t * p_itemid ,
76 /*out*/ vlc_bool_t *play_single_item );
78 static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action,
79 const char *p_varname, char *p_label,
80 const char *p_debug_label );
82 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
84 /****************************************************************************
86 ****************************************************************************/
88 /* FIXME: This variable is a hack. Would be nice to eliminate the
91 static input_thread_t *p_vcd_input = NULL;
93 /* process messages that originate from libcdio. */
95 cdio_log_handler (cdio_log_level_t level, const char message[])
97 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
101 if (p_vcd->i_debug & INPUT_DBG_CDIO)
102 msg_Dbg( p_vcd_input, message);
105 msg_Warn( p_vcd_input, message);
108 case CDIO_LOG_ASSERT:
109 msg_Err( p_vcd_input, message);
112 msg_Warn( p_vcd_input, message,
113 _("The above message had unknown log level"),
119 /* process messages that originate from vcdinfo. */
121 vcd_log_handler (vcd_log_level_t level, const char message[])
123 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
127 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
128 msg_Dbg( p_vcd_input, message);
131 msg_Warn( p_vcd_input, message);
135 msg_Err( p_vcd_input, message);
138 msg_Warn( p_vcd_input, "%s\n%s %d", message,
139 _("The above message had unknown vcdimager log level"),
145 /*****************************************************************************
146 * VCDRead: reads i_len bytes from the VCD into p_buffer.
147 *****************************************************************************
148 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
150 *****************************************************************************/
152 VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
154 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
158 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
162 dbg_print( (INPUT_DBG_CALL), "lsn: %lu",
163 (long unsigned int) p_vcd->cur_lsn );
165 /* Compute the number of blocks we have to read */
167 i_blocks = i_len / M2F2_SECTOR_SIZE;
169 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
172 if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
173 vcdplayer_read_status_t read_status;
175 /* We've run off of the end of this entry. Do we continue or stop? */
176 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
177 "end reached, cur: %lu",
178 (long unsigned int) p_vcd->cur_lsn );
180 read_status = vcdplayer_pbc_is_on( p_vcd )
181 ? vcdplayer_pbc_nav( p_input )
182 : vcdplayer_non_pbc_nav( p_input );
184 switch (read_status) {
186 /* End reached. Return NULL to indicated this. */
188 /* Some sort of error. */
191 case READ_STILL_FRAME:
193 /* Reached the end of a still frame. */
195 byte_t * p_buf = p_buffer;
196 pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;;
198 p_buf += (i_index*M2F2_SECTOR_SIZE);
199 memset(p_buf, 0, M2F2_SECTOR_SIZE);
202 dbg_print(INPUT_DBG_STILL, "Handled still event");
205 p_vcd->p_intf->p_sys->b_still = 1;
206 var_SetInteger( p_input, "state", PAUSE_S );
209 vlc_mutex_lock( &p_input->stream.stream_lock );
211 p_pgrm = p_input->stream.p_selected_program;
212 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
214 vlc_mutex_unlock( &p_input->stream.stream_lock );
216 input_ClockManageControl( p_input, p_pgrm, 0 );
218 p_vcd->p_intf->p_sys->b_still = 1;
219 var_SetInteger( p_input, "state", PAUSE_S );
221 return i_read + M2F2_SECTOR_SIZE;
229 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
231 p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
233 LOG_ERR ("could not read sector %lu",
234 (long unsigned int) p_vcd->cur_lsn );
241 if( p_vcd->b_valid_ep &&
242 /* FIXME kludge so that read does not update chapter
243 * when a manual chapter change was requested and not
244 * yet accomplished */
245 !p_input->stream.p_new_area )
247 unsigned int i_entry = p_input->stream.p_selected_area->i_part;
249 vlc_mutex_lock( &p_input->stream.stream_lock );
251 if( i_entry < p_vcd->num_entries &&
252 p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
254 dbg_print( INPUT_DBG_PBC,
255 "new entry, i_entry %d, sector %lu, es %u",
256 i_entry, (long unsigned int) p_vcd->cur_lsn,
257 p_vcd->p_entries[i_entry] );
258 p_vcd->play_item.num =
259 ++ p_input->stream.p_selected_area->i_part;
260 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
261 VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
262 "chapter", _("Entry"), "Setting entry" );
264 vlc_mutex_unlock( &p_input->stream.stream_lock );
267 i_read += M2F2_SECTOR_SIZE;
270 if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
272 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
273 p_vcd->cur_lsn, p_last_sector ) < 0 )
275 LOG_ERR ("could not read sector %lu",
276 (long unsigned int) p_vcd->cur_lsn );
280 p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
281 p_last_sector, i_len % M2F2_SECTOR_SIZE );
282 i_read += i_len % M2F2_SECTOR_SIZE;
289 /*****************************************************************************
290 * VCDSetProgram: Does nothing since a VCD is mono_program
291 *****************************************************************************/
293 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
295 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
296 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
301 /*****************************************************************************
302 * VCDSetArea: initialize internal data structures and input stream data
303 so set subsequent reading and seeking to reflect that we are
304 at track x, entry or segment y.
305 This is called for each user navigation request, e.g. the GUI
306 Chapter/Title selections or in initial MRL parsing.
307 ****************************************************************************/
309 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
311 thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
312 unsigned int i_entry = p_area->i_part;
313 track_t i_track = p_area->i_id;
314 int old_seekable = p_input->stream.b_seekable;
315 unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb;
317 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
318 "track: %d, entry %d, seekable %d, area %lx, select area %lx ",
319 i_track, i_entry, old_seekable,
320 (long unsigned int) p_area,
321 (long unsigned int) p_input->stream.p_selected_area );
323 /* we can't use the interface slider until initilization is complete */
324 p_input->stream.b_seekable = 0;
326 if( p_area != p_input->stream.p_selected_area )
330 /* If is the result of a track change, make the entry valid. */
331 if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
332 i_entry = p_area->i_plugin_data;
334 /* Change the default area */
335 p_input->stream.p_selected_area = p_area;
337 /* Update the navigation variables without triggering a callback */
339 VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
340 _("Track"), "Setting track");
342 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
343 for( i = p_area->i_plugin_data; i < i_nb; i++ )
345 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
347 p_vcd->play_item.type == VCDINFO_ITEM_TYPE_SEGMENT ?
348 _("Segment"): _("Entry"),
349 "Adding entry choice");
353 unsigned int audio_type =
354 vcdinfo_get_track_audio_type(p_vcd->vcd, i_track);
355 unsigned int i_channels =
356 vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type);
358 var_Change( p_input, "audio_channels", VLC_VAR_CLEARCHOICES, NULL,
361 for( i = 0; i < i_channels; i++ )
363 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
364 "audio_channels", NULL, "Adding audio choice");
371 VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
372 p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
375 VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
376 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
377 p_vcd->p_sectors[i_track+1],
380 p_input->stream.b_seekable = old_seekable;
381 /* warn interface that something has changed */
382 p_input->stream.b_changed = 1;
388 /****************************************************************************
390 ****************************************************************************/
392 VCDSeek( input_thread_t * p_input, off_t i_off )
394 thread_vcd_data_t * p_vcd;
395 unsigned int i_entry=0; /* invalid entry */
397 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
399 p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
401 vlc_mutex_lock( &p_input->stream.stream_lock );
402 #define p_area p_input->stream.p_selected_area
404 if( p_vcd->b_valid_ep )
406 for( i_entry = 0 ; i_entry < p_vcd->num_entries ; i_entry ++ )
408 if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
410 VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
411 "chapter", _("Entry"), "Setting entry" );
415 p_vcd->play_item.num = p_area->i_part = i_entry;
416 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
420 p_input->stream.p_selected_area->i_tell = i_off;
422 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
423 "orig %lu, cur: %lu, offset: %lld, start: %lld, entry %d",
424 (long unsigned int) p_vcd->origin_lsn,
425 (long unsigned int) p_vcd->cur_lsn, i_off,
426 p_input->stream.p_selected_area->i_start, i_entry );
428 vlc_mutex_unlock( &p_input->stream.stream_lock );
431 /*****************************************************************************
432 VCDPlay: set up internal structures so seeking/reading places an item.
433 itemid: the thing to play.
434 user_entry: true if itemid is a user selection (rather than internally-
435 generated selection such as via PBC) in which case we may have to adjust
436 for differences in numbering.
437 *****************************************************************************/
439 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
441 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
442 input_area_t * p_area;
443 vlc_bool_t b_was_still;
445 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
446 itemid.num, itemid.type);
448 if (!p_input->p_access_data) return VLC_EGENERIC;
450 b_was_still = p_vcd->in_still;
452 #define area p_input->stream.pp_areas
454 switch (itemid.type) {
455 case VCDINFO_ITEM_TYPE_TRACK:
457 /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
460 if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
461 LOG_ERR ("Invalid track number %d", itemid.num );
464 p_vcd->in_still = VLC_FALSE;
465 p_area = area[itemid.num];
466 p_area->i_part = p_area->i_plugin_data;
467 p_input->stream.b_seekable = 1;
469 case VCDINFO_ITEM_TYPE_SEGMENT:
470 /* Valid segments go from 0...num_segments-1. */
471 if (itemid.num >= p_vcd->num_segments) {
472 LOG_ERR ( "Invalid segment number: %d", itemid.num );
475 vcdinfo_video_segment_type_t segtype =
476 vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
478 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
479 vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
480 (int) segtype, itemid.num);
483 p_area->i_part = itemid.num;
487 case VCDINFO_FILES_VIDEO_NTSC_STILL:
488 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
489 case VCDINFO_FILES_VIDEO_PAL_STILL:
490 case VCDINFO_FILES_VIDEO_PAL_STILL2:
491 p_input->stream.b_seekable = 0;
492 p_vcd->in_still = VLC_TRUE;
495 p_input->stream.b_seekable = 1;
496 p_vcd->in_still = VLC_FALSE;
501 case VCDINFO_ITEM_TYPE_LID:
502 /* LIDs go from 1..num_lids. */
503 if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
504 LOG_ERR ( "Invalid LID number: %d", itemid.num );
507 p_vcd->cur_lid = itemid.num;
508 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
510 switch (p_vcd->pxd.descriptor_type) {
512 case PSD_TYPE_SELECTION_LIST:
513 case PSD_TYPE_EXT_SELECTION_LIST: {
514 vcdinfo_itemid_t trans_itemid;
515 uint16_t trans_itemid_num;
517 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
518 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
519 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
520 p_vcd->loop_count = 1;
521 p_vcd->loop_item = trans_itemid;
522 return VCDPlay( p_input, trans_itemid );
526 case PSD_TYPE_PLAY_LIST: {
527 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
529 return vcdplayer_inc_play_item(p_input)
530 ? VLC_SUCCESS : VLC_EGENERIC;
534 case PSD_TYPE_END_LIST:
535 case PSD_TYPE_COMMAND_LIST:
542 case VCDINFO_ITEM_TYPE_ENTRY:
543 /* Entries go from 0..num_entries-1. */
544 if (itemid.num >= p_vcd->num_entries) {
545 LOG_ERR ("Invalid entry number: %d", itemid.num );
548 track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
549 p_vcd->in_still = VLC_FALSE;
550 p_area = area[cur_track];
551 p_area->i_part = itemid.num;
552 p_input->stream.b_seekable = 1;
556 LOG_ERR ("unknown entry type" );
560 VCDSetArea( p_input, p_area );
565 if ( p_vcd->in_still != b_was_still ) {
566 if (p_input->stream.pp_selected_es) {
567 var_SetInteger( p_input, "state", PLAYING_S );
572 p_vcd->play_item = itemid;
574 dbg_print( (INPUT_DBG_CALL),
575 "i_start %lld, i_size: %lld, i_tell: %lld, lsn %lu",
576 p_area->i_start, p_area->i_size,
578 (long unsigned int) p_vcd->cur_lsn );
583 /*****************************************************************************
584 VCDEntryPoints: Reads the information about the entry points on the disc
585 and initializes area information with that.
586 Before calling this track information should have been read in.
587 *****************************************************************************/
589 VCDEntryPoints( input_thread_t * p_input )
591 thread_vcd_data_t * p_vcd;
593 unsigned int i, i_entry_index = 0;
594 unsigned int i_previous_track = CDIO_INVALID_TRACK;
596 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
598 i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
602 p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
604 if( p_vcd->p_entries == NULL )
606 LOG_ERR ("not enough memory for entry points treatment" );
610 p_vcd->num_entries = 0;
612 for( i = 0 ; i < i_nb ; i++ )
614 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
615 if( i_track <= p_input->stream.i_area_nb )
617 p_vcd->p_entries[i] =
618 vcdinfo_get_entry_lsn(p_vcd->vcd, i);
619 p_input->stream.pp_areas[i_track]->i_part_nb ++;
621 /* if this entry belongs to a new track */
622 if( i_track != i_previous_track )
624 /* i_plugin_data is used to store the first entry of the area*/
625 p_input->stream.pp_areas[i_track]->i_plugin_data =
627 i_previous_track = i_track;
628 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
631 p_vcd->num_entries ++;
634 msg_Warn( p_input, "wrong track number found in entry points" );
636 p_vcd->b_valid_ep = VLC_TRUE;
640 /*****************************************************************************
641 * VCDSegments: Reads the information about the segments the disc.
642 *****************************************************************************/
644 VCDSegments( input_thread_t * p_input )
646 thread_vcd_data_t * p_vcd;
648 unsigned int num_segments;
651 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
652 num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
654 #define area p_input->stream.pp_areas
656 /* area 0 is reserved for segments. Set Absolute start offset
658 area[0]->i_plugin_data = 0;
659 input_DelArea( p_input, area[0] );
660 input_AddArea( p_input, 0, 0 );
662 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
663 * (off_t)M2F2_SECTOR_SIZE;
664 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
665 * (off_t)M2F2_SECTOR_SIZE;
667 /* Default Segment */
670 /* i_plugin_data is used to store which entry point is the first
671 of the track (area) */
672 area[0]->i_plugin_data = 0;
674 area[0]->i_part_nb = 0;
676 dbg_print( INPUT_DBG_MRL,
677 "area[0] id: %d, i_start: %lld, i_size: %lld",
678 area[0]->i_id, area[0]->i_start, area[0]->i_size );
680 if (num_segments == 0) return 0;
682 /* We have one additional segment allocated so we can get the size
683 by subtracting seg[i+1] - seg[i].
685 p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
686 if( p_vcd->p_segments == NULL )
688 LOG_ERR ("not enough memory for segment treatment" );
692 /* Update the navigation variables without triggering a callback */
693 VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", _("Track"),
696 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
698 for( i = 0 ; i < num_segments ; i++ )
700 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
701 area[0]->i_part_nb ++;
702 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
703 "chapter", _("Segment"), "Adding segment choice");
708 p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
709 vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
714 /*****************************************************************************
715 VCDTracks: initializes area information.
716 Before calling this track information should have been read in.
717 *****************************************************************************/
719 VCDTracks( input_thread_t * p_input )
721 thread_vcd_data_t * p_vcd;
724 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
726 #define area p_input->stream.pp_areas
728 /* We start area addressing for tracks at 1 since the default area 0
729 is reserved for segments */
731 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
733 /* Tracks are Program Chains */
734 input_AddArea( p_input, i, i );
736 /* Absolute start byte offset and byte size */
737 area[i]->i_start = (off_t) p_vcd->p_sectors[i]
738 * (off_t)M2F2_SECTOR_SIZE;
739 area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
740 * (off_t)M2F2_SECTOR_SIZE;
742 /* Current entry being played in track */
745 /* i_plugin_data is used to store which entry point is the first
746 * of the track (area) */
747 area[i]->i_plugin_data = 0;
749 dbg_print( INPUT_DBG_MRL,
750 "area[%d] id: %d, i_start: %lld, i_size: %lld",
751 i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
759 /*****************************************************************************
760 VCDLIDs: Reads the LIST IDs from the LOT.
761 *****************************************************************************/
763 VCDLIDs( input_thread_t * p_input )
765 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
767 p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
768 p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
770 if (vcdinfo_read_psd (p_vcd->vcd)) {
772 vcdinfo_visit_lot (p_vcd->vcd, VLC_FALSE);
776 We need to change libvcdinfo to be more robust when there are
777 problems reading the extended PSD. Given that area-highlighting and
778 selection features in the extended PSD haven't been implemented,
779 it's best then to not try to read this at all.
781 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
782 vcdinfo_visit_lot (p_vcd->vcd, VLC_TRUE);
786 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
787 "num LIDs=%d", p_vcd->num_lids);
792 /*****************************************************************************
793 * VCDParse: parse command line
794 *****************************************************************************/
796 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid,
797 /*out*/ vlc_bool_t *play_single_item )
799 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
804 if( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
805 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
807 *play_single_item = VLC_FALSE;
811 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
816 /* On Win32 we want the VCD access plugin to be explicitly requested,
817 * we end up with lots of problems otherwise */
818 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
821 if( !p_input->psz_name )
826 psz_parser = psz_source = strdup( p_input->psz_name );
828 /* Parse input string :
829 * [device][@[type][title]] */
830 while( *psz_parser && *psz_parser != '@' )
835 if( *psz_parser == '@' )
837 /* Found the divide between the source name and the
838 type+entry number. */
845 switch(*psz_parser) {
847 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
849 *play_single_item = VLC_TRUE;
852 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
854 *play_single_item = VLC_FALSE;
857 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
859 *play_single_item = VLC_TRUE;
862 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
864 *play_single_item = VLC_TRUE;
870 num = strtol( psz_parser, &psz_next, 10 );
871 if ( *psz_parser != '\0' && *psz_next == '\0')
877 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
883 /* No source specified, so figure it out. */
884 if( !p_input->psz_access ) return NULL;
886 psz_source = config_GetPsz( p_input, "vcd" );
888 if( !psz_source || 0==strlen(psz_source) ) {
889 /* Scan for a CD-ROM drive with a VCD in it. */
890 char **cd_drives = cdio_get_devices_with_cap( NULL,
891 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
892 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
894 if( NULL == cd_drives ) return NULL;
895 if( cd_drives[0] == NULL )
897 cdio_free_device_list( cd_drives );
900 psz_source = strdup( cd_drives[0] );
901 cdio_free_device_list( cd_drives );
905 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
906 "source=%s entry=%d type=%d",
907 psz_source, p_itemid->num, p_itemid->type);
913 Set's start origin subsequent seeks/reads
916 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
917 lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
919 thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
921 p_vcd->origin_lsn = origin_lsn;
922 p_vcd->cur_lsn = cur_lsn;
923 p_vcd->end_lsn = end_lsn;
924 p_vcd->cur_track = cur_track;
925 p_vcd->play_item.num = cur_entry;
926 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
928 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
929 "origin: %lu, cur_lsn: %lu, end_lsn: %lu, entry: %d, track: %d",
930 (long unsigned int) origin_lsn,
931 (long unsigned int) cur_lsn,
932 (long unsigned int) end_lsn, cur_entry, cur_track );
934 p_input->stream.p_selected_area->i_tell =
935 (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
937 VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
939 p_vcd->play_item.type == VCDINFO_ITEM_TYPE_ENTRY ?
940 _("Entry") : _("Segment"),
941 "Setting entry/segment");
944 /*****************************************************************************
945 * vcd_Open: Opens a VCD device or file and returns an opaque handle
946 *****************************************************************************/
947 static vcdinfo_obj_t *
948 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
950 vcdinfo_obj_t *p_vcdobj;
953 if( !psz_dev ) return NULL;
955 actual_dev=strdup(psz_dev);
956 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
966 /****************************************************************************
967 * VCDReadSector: Read a sector (2324 bytes)
968 ****************************************************************************/
970 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
971 lsn_t cur_lsn, byte_t * p_buffer )
974 uint8_t subheader [8];
975 uint8_t data [M2F2_SECTOR_SIZE];
978 vcdsector_t vcd_sector;
980 if( cdio_read_mode2_sector( vcdinfo_get_cd_image( p_vcd ),
981 &vcd_sector, cur_lsn, VLC_TRUE )
984 msg_Warn( p_this, "Could not read LSN %lu",
985 (long unsigned int) cur_lsn );
989 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
994 /****************************************************************************
995 Update the "varname" variable to i_num without triggering a callback.
996 ****************************************************************************/
998 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
999 const char *p_varname, char *p_label,
1000 const char *p_debug_label)
1004 if (NULL != p_vcd_input) {
1005 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1006 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
1010 text.psz_string = p_label;
1011 var_Change( p_input, p_varname, VLC_VAR_SETTEXT, &text, NULL );
1013 var_Change( p_input, p_varname, i_action, &val, NULL );
1018 MetaInfoAddStr(input_thread_t *p_input, char *p_cat,
1019 char *title, const char *str)
1021 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1023 dbg_print( INPUT_DBG_META, "field: %s: %s\n", title, str);
1024 input_Control( p_input, INPUT_ADD_INFO, p_cat, title, "%s", str);
1030 MetaInfoAddNum(input_thread_t *p_input, char *p_cat, char *title, int num)
1032 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1033 dbg_print( INPUT_DBG_META, "field %s: %d\n", title, num);
1034 input_Control( p_input, INPUT_ADD_INFO, p_cat, title, "%d", num );
1037 #define addstr(title, str) \
1038 MetaInfoAddStr( p_input, p_cat, title, str );
1040 #define addnum(title, num) \
1041 MetaInfoAddNum( p_input, p_cat, title, num );
1043 static void InformationCreate( input_thread_t *p_input )
1045 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1046 unsigned int i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
1047 unsigned int last_entry = 0;
1051 p_cat = _("General");
1053 addstr( _("VCD Format"), vcdinfo_get_format_version_str(p_vcd->vcd) );
1054 addstr( _("Album"), vcdinfo_get_album_id(p_vcd->vcd));
1055 addstr( _("Application"), vcdinfo_get_application_id(p_vcd->vcd) );
1056 addstr( _("Preparer"), vcdinfo_get_preparer_id(p_vcd->vcd) );
1057 addnum( _("Vol #"), vcdinfo_get_volume_num(p_vcd->vcd) );
1058 addnum( _("Vol max #"), vcdinfo_get_volume_count(p_vcd->vcd) );
1059 addstr( _("Volume Set"), vcdinfo_get_volumeset_id(p_vcd->vcd) );
1060 addstr( _("Volume"), vcdinfo_get_volume_id(p_vcd->vcd) );
1061 addstr( _("Publisher"), vcdinfo_get_publisher_id(p_vcd->vcd) );
1062 addstr( _("System Id"), vcdinfo_get_system_id(p_vcd->vcd) );
1063 addnum( "LIDs", vcdinfo_get_num_LIDs(p_vcd->vcd) );
1064 addnum( _("Entries"), vcdinfo_get_num_entries(p_vcd->vcd) );
1065 addnum( _("Segments"), vcdinfo_get_num_segments(p_vcd->vcd) );
1066 addnum( _("Tracks"), vcdinfo_get_num_tracks(p_vcd->vcd) );
1068 /* Spit out track information. Could also include MSF info.
1071 #define TITLE_MAX 30
1072 for( i_track = 1 ; i_track < p_vcd->num_tracks ; i_track++ ) {
1073 char psz_track[TITLE_MAX];
1074 unsigned int audio_type = vcdinfo_get_track_audio_type(p_vcd->vcd,
1076 snprintf(psz_track, TITLE_MAX, "%s%02d", _("Track "), i_track);
1080 addnum(_("Audio Channels"),
1081 vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type) );
1084 addnum(_("First Entry Point"), last_entry );
1085 for ( ; last_entry < i_nb
1086 && vcdinfo_get_track(p_vcd->vcd, last_entry) == i_track;
1088 addnum(_("Last Entry Point"), last_entry-1 );
1092 #define add_format_str_info(val) \
1094 const char *str = val; \
1096 if (val != NULL) { \
1099 strncat(tp, str, TEMP_STR_LEN-(tp-temp_str)); \
1102 saw_control_prefix = VLC_FALSE; \
1106 #define add_format_num_info( val, fmt ) \
1110 sprintf(num_str, fmt, val); \
1111 len = strlen(num_str); \
1114 strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str)); \
1117 saw_control_prefix = VLC_FALSE; \
1121 Take a format string and expand escape sequences, that is sequences that
1122 begin with %, with information from the current VCD.
1123 The expanded string is returned. Here is a list of escape sequences:
1125 %A : The album information
1126 %C : The VCD volume count - the number of CD's in the collection.
1127 %c : The VCD volume num - the number of the CD in the collection.
1128 %F : The VCD Format, e.g. VCD 1.0, VCD 1.1, VCD 2.0, or SVCD
1129 %I : The current entry/segment/playback type, e.g. ENTRY, TRACK, SEGMENT...
1130 %L : The playlist ID prefixed with " LID" if it exists
1132 %N : The current number of the %I - a decimal number
1133 %P : The publisher ID
1134 %p : The preparer ID
1135 %S : If we are in a segment (menu), the kind of segment
1136 %T : The track number
1137 %V : The volume set ID
1139 A number between 1 and the volume count.
1143 VCDFormatStr(const input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1144 const char format_str[], const char *mrl,
1145 const vcdinfo_itemid_t *itemid)
1147 #define TEMP_STR_SIZE 256
1148 #define TEMP_STR_LEN (TEMP_STR_SIZE-1)
1149 static char temp_str[TEMP_STR_SIZE];
1151 char * tp = temp_str;
1152 vlc_bool_t saw_control_prefix = VLC_FALSE;
1153 size_t format_len = strlen(format_str);
1155 memset(temp_str, 0, TEMP_STR_SIZE);
1157 for (i=0; i<format_len; i++) {
1159 if (!saw_control_prefix && format_str[i] != '%') {
1160 *tp++ = format_str[i];
1161 saw_control_prefix = VLC_FALSE;
1165 switch(format_str[i]) {
1167 if (saw_control_prefix) {
1170 saw_control_prefix = !saw_control_prefix;
1173 add_format_str_info(vcdinfo_strip_trail(vcdinfo_get_album_id(p_vcd->vcd),
1178 add_format_num_info(vcdinfo_get_volume_num(p_vcd->vcd), "%d");
1182 add_format_num_info(vcdinfo_get_volume_count(p_vcd->vcd), "%d");
1186 add_format_str_info(vcdinfo_get_format_version_str(p_vcd->vcd));
1191 switch (itemid->type) {
1192 case VCDINFO_ITEM_TYPE_TRACK:
1193 strncat(tp, _("Track"), TEMP_STR_LEN-(tp-temp_str));
1194 tp += strlen(_("Track"));
1196 case VCDINFO_ITEM_TYPE_ENTRY:
1197 strncat(tp, _("Entry"), TEMP_STR_LEN-(tp-temp_str));
1198 tp += strlen(_("Entry"));
1200 case VCDINFO_ITEM_TYPE_SEGMENT:
1201 strncat(tp, _("Segment"), TEMP_STR_LEN-(tp-temp_str));
1202 tp += strlen(_("Segment"));
1204 case VCDINFO_ITEM_TYPE_LID:
1205 strncat(tp, _("List ID"), TEMP_STR_LEN-(tp-temp_str));
1206 tp += strlen(_("List ID"));
1208 case VCDINFO_ITEM_TYPE_SPAREID2:
1209 strncat(tp, _("Navigation"), TEMP_STR_LEN-(tp-temp_str));
1210 tp += strlen(_("Navigation"));
1216 saw_control_prefix = VLC_FALSE;
1221 if (vcdplayer_pbc_is_on(p_vcd)) {
1223 sprintf(num_str, "%s %d", _("List ID"), p_vcd->cur_lid);
1224 strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));
1225 tp += strlen(num_str);
1227 saw_control_prefix = VLC_FALSE;
1231 add_format_str_info(mrl);
1235 add_format_num_info(itemid->num, "%d");
1239 add_format_str_info(vcdinfo_get_preparer_id(p_vcd->vcd));
1243 add_format_str_info(vcdinfo_get_publisher_id(p_vcd->vcd));
1247 if ( VCDINFO_ITEM_TYPE_SEGMENT==itemid->type ) {
1248 char seg_type_str[10];
1250 sprintf(seg_type_str, " %s",
1251 vcdinfo_video_type2str(p_vcd->vcd, itemid->num));
1252 strncat(tp, seg_type_str, TEMP_STR_LEN-(tp-temp_str));
1253 tp += strlen(seg_type_str);
1255 saw_control_prefix = VLC_FALSE;
1259 add_format_num_info(p_vcd->cur_track, "%d");
1263 add_format_str_info(vcdinfo_get_volumeset_id(p_vcd->vcd));
1267 add_format_str_info(vcdinfo_get_volume_id(p_vcd->vcd));
1272 *tp++ = format_str[i];
1273 saw_control_prefix = VLC_FALSE;
1276 return strdup(temp_str);
1280 VCDCreatePlayListItem(const input_thread_t *p_input,
1281 thread_vcd_data_t *p_vcd,
1282 playlist_t *p_playlist,
1283 const vcdinfo_itemid_t *itemid,
1284 char *psz_mrl, int psz_mrl_max,
1285 const char *psz_source, int playlist_operation,
1292 switch(itemid->type) {
1293 case VCDINFO_ITEM_TYPE_TRACK:
1296 case VCDINFO_ITEM_TYPE_SEGMENT:
1299 case VCDINFO_ITEM_TYPE_LID:
1302 case VCDINFO_ITEM_TYPE_ENTRY:
1310 snprintf(psz_mrl, psz_mrl_max, "%s%s@%c%u", VCD_MRL_PREFIX, psz_source,
1311 c_type, itemid->num);
1314 VCDFormatStr( p_input, p_vcd,
1315 config_GetPsz( p_input, MODULE_STRING "-title-format" ),
1318 playlist_Add( p_playlist, psz_mrl, p_title, playlist_operation, i_pos );
1321 VCDFormatStr( p_input, p_vcd,
1322 config_GetPsz( p_input, MODULE_STRING "-author-format" ),
1325 if( i_pos == PLAYLIST_END ) i_pos = p_playlist->i_size - 1;
1326 playlist_AddInfo(p_playlist, i_pos, _("General"), _("Author"), "%s",
1331 VCDFixupPlayList( input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1332 const char *psz_source, vcdinfo_itemid_t *itemid,
1333 vlc_bool_t play_single_item )
1336 playlist_t * p_playlist;
1338 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) +
1339 strlen("@T") + strlen("100") + 1;
1341 psz_mrl = malloc( psz_mrl_max );
1343 if( psz_mrl == NULL )
1345 msg_Warn( p_input, "out of memory" );
1349 p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1353 msg_Warn( p_input, "can't find playlist" );
1358 if ( play_single_item )
1360 /* May fill out more information when the playlist user interface becomes
1363 VCDCreatePlayListItem(p_input, p_vcd, p_playlist, itemid,
1364 psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE,
1365 p_playlist->i_index);
1370 vcdinfo_itemid_t list_itemid;
1371 list_itemid.type=VCDINFO_ITEM_TYPE_ENTRY;
1373 playlist_LockDelete( p_playlist, p_playlist->i_index);
1375 for( i = 0 ; i < p_vcd->num_entries ; i++ )
1378 VCDCreatePlayListItem(p_input, p_vcd, p_playlist, &list_itemid,
1379 psz_mrl, psz_mrl_max, psz_source,
1380 PLAYLIST_APPEND, PLAYLIST_END);
1383 playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
1387 vlc_object_release( p_playlist );
1392 /*****************************************************************************
1394 *****************************************************************************/
1396 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
1397 vlc_value_t oldval, vlc_value_t val, void *p_data )
1399 thread_vcd_data_t *p_vcd;
1401 if (NULL == p_vcd_input) return VLC_EGENERIC;
1403 p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1405 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
1406 msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
1407 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
1409 p_vcd->i_debug = val.i_int;
1415 The front-ends change spu-es - which sort of represents a symbolic
1416 name. Internally we use spu-channel which runs from 0..3.
1418 So we add a callback to intercept changes to spu-es and change them
1419 to updates to spu-channel. Ugly.
1424 VCDSPUCallback( vlc_object_t *p_this, const char *psz_variable,
1425 vlc_value_t old_val, vlc_value_t new_val, void *param)
1428 input_thread_t *p_input = (input_thread_t *)p_this;
1429 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
1432 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EVENT), "old_val: %x, new_val %x",
1433 old_val.i_int, new_val.i_int);
1435 val.i_int = new_val.i_int;
1436 var_Set( p_this, "spu-channel", val );
1441 /*****************************************************************************
1443 read in meta-information about VCD: the number of tracks, segments,
1444 entries, size and starting information. Then set up state variables so
1445 that we read/seek starting at the location specified.
1447 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
1448 and VLC_EGENERIC for some other error.
1449 *****************************************************************************/
1451 E_(Open) ( vlc_object_t *p_this )
1453 input_thread_t * p_input = (input_thread_t *)p_this;
1454 thread_vcd_data_t * p_vcd;
1456 vcdinfo_itemid_t itemid;
1457 vlc_bool_t b_play_ok;
1458 vlc_bool_t play_single_item = VLC_FALSE;
1460 p_input->pf_read = VCDRead;
1461 p_input->pf_seek = VCDSeek;
1462 p_input->pf_set_area = VCDSetArea;
1463 p_input->pf_set_program = VCDSetProgram;
1465 p_vcd = malloc( sizeof(thread_vcd_data_t) );
1469 LOG_ERR ("out of memory" );
1473 p_input->p_access_data = (void *)p_vcd;
1474 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
1475 p_vcd->in_still = VLC_FALSE;
1476 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
1478 /* Set where to log errors messages from libcdio. */
1479 p_vcd_input = (input_thread_t *)p_this;
1480 cdio_log_set_handler ( cdio_log_handler );
1481 vcd_log_set_handler ( vcd_log_handler );
1483 psz_source = VCDParse( p_input, &itemid, &play_single_item );
1485 if ( NULL == psz_source )
1488 return( VLC_EGENERIC );
1491 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1492 psz_source, p_input->psz_name );
1494 p_vcd->p_segments = NULL;
1495 p_vcd->p_entries = NULL;
1498 p_input->i_mtu = VCD_DATA_ONCE;
1500 vlc_mutex_lock( &p_input->stream.stream_lock );
1502 /* If we are here we can control the pace... */
1503 p_input->stream.b_pace_control = 1;
1505 p_input->stream.b_seekable = 1;
1506 p_input->stream.p_selected_area->i_size = 0;
1507 p_input->stream.p_selected_area->i_tell = 0;
1509 vlc_mutex_unlock( &p_input->stream.stream_lock );
1511 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1513 msg_Warn( p_input, "could not open %s", psz_source );
1517 p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
1519 /* Get track information. */
1520 p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
1521 vcdinfo_get_cd_image(p_vcd->vcd),
1522 &p_vcd->p_sectors );
1523 if( p_vcd->num_tracks < 0 )
1524 LOG_ERR ("unable to count tracks" );
1525 else if( p_vcd->num_tracks <= 1 )
1526 LOG_ERR ("no movie tracks found" );
1527 if( p_vcd->num_tracks <= 1)
1529 vcdinfo_close( p_vcd->vcd );
1533 /* Set stream and area data */
1534 vlc_mutex_lock( &p_input->stream.stream_lock );
1536 /* Initialize ES structures */
1537 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
1539 /* disc input method */
1540 p_input->stream.i_method = INPUT_METHOD_VCD;
1542 p_input->stream.i_area_nb = 1;
1545 /* Initialize segment information. */
1546 VCDSegments( p_input );
1548 /* Initialize track area information. */
1549 VCDTracks( p_input );
1551 if( VCDEntryPoints( p_input ) < 0 )
1553 msg_Warn( p_input, "could not read entry points, will not use them" );
1554 p_vcd->b_valid_ep = VLC_FALSE;
1557 if( VCDLIDs( p_input ) < 0 )
1559 msg_Warn( p_input, "could not read entry LIDs" );
1562 b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
1564 vlc_mutex_unlock( &p_input->stream.stream_lock );
1566 if ( ! b_play_ok ) {
1567 vcdinfo_close( p_vcd->vcd );
1571 if( !p_input->psz_demux || !*p_input->psz_demux )
1574 p_input->psz_demux = "vcdx";
1576 p_input->psz_demux = "ps";
1580 p_vcd->p_intf = intf_Create( p_input, "vcdx" );
1581 p_vcd->p_intf->b_block = VLC_FALSE;
1582 intf_RunThread( p_vcd->p_intf );
1584 InformationCreate( p_input );
1586 if (play_single_item)
1587 VCDFixupPlayList( p_input, p_vcd, psz_source, &itemid,
1592 var_AddCallback( p_this, "spu-es", VCDSPUCallback, NULL );
1599 return VLC_EGENERIC;
1602 /*****************************************************************************
1603 * Close: closes VCD releasing allocated memory.
1604 *****************************************************************************/
1606 E_(Close) ( vlc_object_t *p_this )
1608 input_thread_t * p_input = (input_thread_t *)p_this;
1609 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
1611 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1613 var_DelCallback( p_this, "spu-es", VCDSPUCallback, NULL );
1614 vcdinfo_close( p_vcd->vcd );
1616 free( p_vcd->p_entries );
1617 free( p_vcd->p_segments );
1618 free( p_vcd->p_sectors );
1620 /* For reasons that are a mystery to me we don't have to deal with
1621 stopping, and destroying the p_vcd->p_intf thread. And if we do
1622 it causes problems upstream.
1624 if( p_vcd->p_intf != NULL )
1626 p_vcd->p_intf = NULL;
1630 p_input->p_access_data = NULL;