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*/ bool *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 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
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 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
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;
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 = 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 = true;
495 p_input->stream.b_seekable = 1;
496 p_vcd->in_still = 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 = 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 input_SetStatus( p_input, INPUT_STATUS_END );
568 input_SetStatus( p_input, INPUT_STATUS_PLAY );
573 p_vcd->play_item = itemid;
575 dbg_print( (INPUT_DBG_CALL),
576 "i_start %lld, i_size: %lld, i_tell: %lld, lsn %lu",
577 p_area->i_start, p_area->i_size,
579 (long unsigned int) p_vcd->cur_lsn );
584 /*****************************************************************************
585 VCDEntryPoints: Reads the information about the entry points on the disc
586 and initializes area information with that.
587 Before calling this track information should have been read in.
588 *****************************************************************************/
590 VCDEntryPoints( input_thread_t * p_input )
592 thread_vcd_data_t * p_vcd;
594 unsigned int i, i_entry_index = 0;
595 unsigned int i_previous_track = CDIO_INVALID_TRACK;
597 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
599 i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
603 p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
605 if( p_vcd->p_entries == NULL )
607 LOG_ERR ("not enough memory for entry points treatment" );
611 p_vcd->num_entries = 0;
613 for( i = 0 ; i < i_nb ; i++ )
615 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
616 if( i_track <= p_input->stream.i_area_nb )
618 p_vcd->p_entries[i] =
619 vcdinfo_get_entry_lsn(p_vcd->vcd, i);
620 p_input->stream.pp_areas[i_track]->i_part_nb ++;
622 /* if this entry belongs to a new track */
623 if( i_track != i_previous_track )
625 /* i_plugin_data is used to store the first entry of the area*/
626 p_input->stream.pp_areas[i_track]->i_plugin_data =
628 i_previous_track = i_track;
629 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
632 p_vcd->num_entries ++;
635 msg_Warn( p_input, "wrong track number found in entry points" );
637 p_vcd->b_valid_ep = true;
641 /*****************************************************************************
642 * VCDSegments: Reads the information about the segments the disc.
643 *****************************************************************************/
645 VCDSegments( input_thread_t * p_input )
647 thread_vcd_data_t * p_vcd;
649 unsigned int num_segments;
652 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
653 num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
655 #define area p_input->stream.pp_areas
657 /* area 0 is reserved for segments. Set Absolute start offset
659 area[0]->i_plugin_data = 0;
660 input_DelArea( p_input, area[0] );
661 input_AddArea( p_input, 0, 0 );
663 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
664 * (off_t)M2F2_SECTOR_SIZE;
665 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
666 * (off_t)M2F2_SECTOR_SIZE;
668 /* Default Segment */
671 /* i_plugin_data is used to store which entry point is the first
672 of the track (area) */
673 area[0]->i_plugin_data = 0;
675 area[0]->i_part_nb = 0;
677 dbg_print( INPUT_DBG_MRL,
678 "area[0] id: %d, i_start: %lld, i_size: %lld",
679 area[0]->i_id, area[0]->i_start, area[0]->i_size );
681 if (num_segments == 0) return 0;
683 /* We have one additional segment allocated so we can get the size
684 by subtracting seg[i+1] - seg[i].
686 p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
687 if( p_vcd->p_segments == NULL )
689 LOG_ERR ("not enough memory for segment treatment" );
693 /* Update the navigation variables without triggering a callback */
694 VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", _("Track"),
697 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
699 for( i = 0 ; i < num_segments ; i++ )
701 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
702 area[0]->i_part_nb ++;
703 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
704 "chapter", _("Segment"), "Adding segment choice");
709 p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
710 vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
715 /*****************************************************************************
716 VCDTracks: initializes area information.
717 Before calling this track information should have been read in.
718 *****************************************************************************/
720 VCDTracks( input_thread_t * p_input )
722 thread_vcd_data_t * p_vcd;
725 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
727 #define area p_input->stream.pp_areas
729 /* We start area addressing for tracks at 1 since the default area 0
730 is reserved for segments */
732 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
734 /* Tracks are Program Chains */
735 input_AddArea( p_input, i, i );
737 /* Absolute start byte offset and byte size */
738 area[i]->i_start = (off_t) p_vcd->p_sectors[i]
739 * (off_t)M2F2_SECTOR_SIZE;
740 area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
741 * (off_t)M2F2_SECTOR_SIZE;
743 /* Current entry being played in track */
746 /* i_plugin_data is used to store which entry point is the first
747 * of the track (area) */
748 area[i]->i_plugin_data = 0;
750 dbg_print( INPUT_DBG_MRL,
751 "area[%d] id: %d, i_start: %lld, i_size: %lld",
752 i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
760 /*****************************************************************************
761 VCDLIDs: Reads the LIST IDs from the LOT.
762 *****************************************************************************/
764 VCDLIDs( input_thread_t * p_input )
766 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
768 p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
769 p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
771 if (vcdinfo_read_psd (p_vcd->vcd)) {
773 vcdinfo_visit_lot (p_vcd->vcd, false);
777 We need to change libvcdinfo to be more robust when there are
778 problems reading the extended PSD. Given that area-highlighting and
779 selection features in the extended PSD haven't been implemented,
780 it's best then to not try to read this at all.
782 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
783 vcdinfo_visit_lot (p_vcd->vcd, true);
787 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
788 "num LIDs=%d", p_vcd->num_lids);
793 /*****************************************************************************
794 * VCDParse: parse command line
795 *****************************************************************************/
797 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid,
798 /*out*/ bool *play_single_item )
800 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
805 if ( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
806 p_itemid->type=VCDINFO_ITEM_TYPE_LID;
808 *play_single_item=false;
810 p_itemid->type=VCDINFO_ITEM_TYPE_ENTRY;
815 /* On Win32 we want the VCD access plugin to be explicitly requested,
816 * we end up with lots of problems otherwise */
817 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
820 if( !p_input->psz_name )
825 psz_parser = psz_source = strdup( p_input->psz_name );
827 /* Parse input string :
828 * [device][@[type][title]] */
829 while( *psz_parser && *psz_parser != '@' )
834 if( *psz_parser == '@' )
836 /* Found the divide between the source name and the
837 type+entry number. */
844 switch(*psz_parser) {
846 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
848 *play_single_item = true;
851 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
853 *play_single_item = false;
856 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
858 *play_single_item = true;
861 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
863 *play_single_item = true;
869 num = strtol( psz_parser, &psz_next, 10 );
870 if ( *psz_parser != '\0' && *psz_next == '\0')
876 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
882 /* No source specified, so figure it out. */
883 if( !p_input->psz_access ) return NULL;
885 psz_source = config_GetPsz( p_input, "vcd" );
887 if( !psz_source || 0==strlen(psz_source) ) {
888 /* Scan for a CD-ROM drive with a VCD in it. */
889 char **cd_drives = cdio_get_devices_with_cap(NULL,
890 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
891 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
893 if (NULL == cd_drives) return NULL;
894 if (cd_drives[0] == NULL) {
895 cdio_free_device_list(cd_drives);
898 psz_source = strdup(cd_drives[0]);
899 cdio_free_device_list(cd_drives);
903 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
904 "source=%s entry=%d type=%d",
905 psz_source, p_itemid->num, p_itemid->type);
911 Set's start origin subsequent seeks/reads
914 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
915 lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
917 thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
919 p_vcd->origin_lsn = origin_lsn;
920 p_vcd->cur_lsn = cur_lsn;
921 p_vcd->end_lsn = end_lsn;
922 p_vcd->cur_track = cur_track;
923 p_vcd->play_item.num = cur_entry;
924 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
926 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
927 "origin: %lu, cur_lsn: %lu, end_lsn: %lu, entry: %d, track: %d",
928 (long unsigned int) origin_lsn,
929 (long unsigned int) cur_lsn,
930 (long unsigned int) end_lsn, cur_entry, cur_track );
932 p_input->stream.p_selected_area->i_tell =
933 (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
935 VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
937 p_vcd->play_item.type == VCDINFO_ITEM_TYPE_ENTRY ?
938 _("Entry") : _("Segment"),
939 "Setting entry/segment");
942 /*****************************************************************************
943 * vcd_Open: Opens a VCD device or file and returns an opaque handle
944 *****************************************************************************/
945 static vcdinfo_obj_t *
946 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
948 vcdinfo_obj_t *p_vcdobj;
951 if( !psz_dev ) return NULL;
953 actual_dev=strdup(psz_dev);
954 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
964 /****************************************************************************
965 * VCDReadSector: Read a sector (2324 bytes)
966 ****************************************************************************/
968 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
969 lsn_t cur_lsn, byte_t * p_buffer )
972 uint8_t subheader [8];
973 uint8_t data [M2F2_SECTOR_SIZE];
976 vcdsector_t vcd_sector;
978 if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
979 &vcd_sector, cur_lsn, true)
982 msg_Warn( p_this, "Could not read LSN %lu",
983 (long unsigned int) cur_lsn );
987 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
992 /****************************************************************************
993 Update the "varname" variable to i_num without triggering a callback.
994 ****************************************************************************/
996 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
997 const char *p_varname, char *p_label,
998 const char *p_debug_label)
1002 if (NULL != p_vcd_input) {
1003 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1004 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
1008 text.psz_string = p_label;
1009 var_Change( p_input, p_varname, VLC_VAR_SETTEXT, &text, NULL );
1011 var_Change( p_input, p_varname, i_action, &val, NULL );
1016 MetaInfoAddStr(input_thread_t *p_input, input_info_category_t *p_cat,
1017 playlist_t *p_playlist, char *title,
1020 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1021 playlist_item_t *p_item;
1023 dbg_print( INPUT_DBG_META, "field: %s: %s\n", title, str);
1024 input_AddInfo( p_cat, title, "%s", str );
1026 vlc_mutex_lock( &p_playlist->object_lock );
1027 p_item = playlist_ItemGetByPos( p_playlist, -1 );
1028 vlc_mutex_unlock( &p_playlist->object_lock );
1030 vlc_mutex_lock( &p_item->lock );
1031 playlist_ItemAddInfo( p_item, p_cat->psz_name, title,
1033 vlc_mutex_unlock( &p_item->lock );
1039 MetaInfoAddNum(input_thread_t *p_input, input_info_category_t *p_cat,
1040 playlist_t *p_playlist, char *title, int num)
1042 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1043 playlist_item_t *p_item;
1045 vlc_mutex_lock( &p_playlist->object_lock );
1046 p_item = playlist_ItemGetByPos( p_playlist, -1 );
1047 vlc_mutex_unlock( &p_playlist->object_lock );
1049 dbg_print( INPUT_DBG_META, "field %s: %d\n", title, num);
1050 input_AddInfo( p_cat, title, "%d", num );
1052 vlc_mutex_lock( &p_item->lock );
1053 playlist_ItemAddInfo( p_item , p_cat->psz_name, title, "%d",num );
1054 vlc_mutex_unlock( &p_item->lock );
1057 #define addstr(title, str) \
1058 MetaInfoAddStr( p_input, p_cat, p_playlist, title, str );
1060 #define addnum(title, num) \
1061 MetaInfoAddNum( p_input, p_cat, p_playlist, title, num );
1063 static void InformationCreate( input_thread_t *p_input )
1065 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1066 unsigned int i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
1067 unsigned int last_entry = 0;
1068 input_info_category_t *p_cat;
1070 playlist_t *p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1073 p_cat = input_InfoCategory( p_input, "General" );
1075 addstr( _("VCD Format"), vcdinfo_get_format_version_str(p_vcd->vcd) );
1076 addstr( _("Album"), vcdinfo_get_album_id(p_vcd->vcd));
1077 addstr( _("Application"), vcdinfo_get_application_id(p_vcd->vcd) );
1078 addstr( _("Preparer"), vcdinfo_get_preparer_id(p_vcd->vcd) );
1079 addnum( _("Vol #"), vcdinfo_get_volume_num(p_vcd->vcd) );
1080 addnum( _("Vol max #"), vcdinfo_get_volume_count(p_vcd->vcd) );
1081 addstr( _("Volume Set"), vcdinfo_get_volumeset_id(p_vcd->vcd) );
1082 addstr( _("Volume"), vcdinfo_get_volume_id(p_vcd->vcd) );
1083 addstr( _("Publisher"), vcdinfo_get_publisher_id(p_vcd->vcd) );
1084 addstr( _("System Id"), vcdinfo_get_system_id(p_vcd->vcd) );
1085 addnum( "LIDs", vcdinfo_get_num_LIDs(p_vcd->vcd) );
1086 addnum( _("Entries"), vcdinfo_get_num_entries(p_vcd->vcd) );
1087 addnum( _("Segments"), vcdinfo_get_num_segments(p_vcd->vcd) );
1088 addnum( _("Tracks"), vcdinfo_get_num_tracks(p_vcd->vcd) );
1090 /* Spit out track information. Could also include MSF info.
1093 #define TITLE_MAX 30
1094 for( i_track = 1 ; i_track < p_vcd->num_tracks ; i_track++ ) {
1095 char track_str[TITLE_MAX];
1096 unsigned int audio_type = vcdinfo_get_track_audio_type(p_vcd->vcd,
1098 snprintf(track_str, TITLE_MAX, "%s%02d", _("Track"), i_track);
1099 p_cat = input_InfoCategory( p_input, track_str );
1102 addnum(_("Audio Channels"),
1103 vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type) );
1106 addnum(_("First Entry Point"), last_entry );
1107 for ( ; last_entry < i_nb
1108 && vcdinfo_get_track(p_vcd->vcd, last_entry) == i_track;
1110 addnum(_("Last Entry Point"), last_entry-1 );
1114 #define add_format_str_info(val) \
1116 const char *str = val; \
1118 if (val != NULL) { \
1121 strncat(tp, str, TEMP_STR_LEN-(tp-temp_str)); \
1124 saw_control_prefix = false; \
1128 #define add_format_num_info(val, fmt) \
1132 sprintf(num_str, fmt, val); \
1133 len=strlen(num_str); \
1135 strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str)); \
1138 saw_control_prefix = false; \
1142 Take a format string and expand escape sequences, that is sequences that
1143 begin with %, with information from the current VCD.
1144 The expanded string is returned. Here is a list of escape sequences:
1146 %A : The album information
1147 %C : The VCD volume count - the number of CD's in the collection.
1148 %c : The VCD volume num - the number of the CD in the collection.
1149 %F : The VCD Format, e.g. VCD 1.0, VCD 1.1, VCD 2.0, or SVCD
1150 %I : The current entry/segment/playback type, e.g. ENTRY, TRACK, SEGMENT...
1151 %L : The playlist ID prefixed with " LID" if it exists
1153 %N : The current number of the %I - a decimal number
1154 %P : The publisher ID
1155 %p : The preparer ID
1156 %S : If we are in a segment (menu), the kind of segment
1157 %T : The track number
1158 %V : The volume set ID
1160 A number between 1 and the volume count.
1164 VCDFormatStr(const input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1165 const char format_str[], const char *mrl,
1166 const vcdinfo_itemid_t *itemid)
1168 #define TEMP_STR_SIZE 256
1169 #define TEMP_STR_LEN (TEMP_STR_SIZE-1)
1170 static char temp_str[TEMP_STR_SIZE];
1172 char * tp = temp_str;
1173 bool saw_control_prefix = false;
1174 size_t format_len = strlen(format_str);
1176 bzero(temp_str, TEMP_STR_SIZE);
1178 for (i=0; i<format_len; i++) {
1180 if (!saw_control_prefix && format_str[i] != '%') {
1181 *tp++ = format_str[i];
1182 saw_control_prefix = false;
1186 switch(format_str[i]) {
1188 if (saw_control_prefix) {
1191 saw_control_prefix = !saw_control_prefix;
1194 add_format_str_info(vcdinfo_strip_trail(vcdinfo_get_album_id(p_vcd->vcd),
1199 add_format_num_info(vcdinfo_get_volume_num(p_vcd->vcd), "%d");
1203 add_format_num_info(vcdinfo_get_volume_count(p_vcd->vcd), "%d");
1207 add_format_str_info(vcdinfo_get_format_version_str(p_vcd->vcd));
1212 switch (itemid->type) {
1213 case VCDINFO_ITEM_TYPE_TRACK:
1214 strncat(tp, _("Track"), TEMP_STR_LEN-(tp-temp_str));
1215 tp += strlen(_("Track"));
1217 case VCDINFO_ITEM_TYPE_ENTRY:
1218 strncat(tp, _("Entry"), TEMP_STR_LEN-(tp-temp_str));
1219 tp += strlen(_("Entry"));
1221 case VCDINFO_ITEM_TYPE_SEGMENT:
1222 strncat(tp, _("Segment"), TEMP_STR_LEN-(tp-temp_str));
1223 tp += strlen(_("Segment"));
1225 case VCDINFO_ITEM_TYPE_LID:
1226 strncat(tp, _("List ID"), TEMP_STR_LEN-(tp-temp_str));
1227 tp += strlen(_("List ID"));
1229 case VCDINFO_ITEM_TYPE_SPAREID2:
1230 strncat(tp, _("Navigation"), TEMP_STR_LEN-(tp-temp_str));
1231 tp += strlen(_("Navigation"));
1237 saw_control_prefix = false;
1242 if (vcdplayer_pbc_is_on(p_vcd)) {
1244 sprintf(num_str, "%s %d", _("List ID"), p_vcd->cur_lid);
1245 strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));
1246 tp += strlen(num_str);
1248 saw_control_prefix = false;
1252 add_format_str_info(mrl);
1256 add_format_num_info(itemid->num, "%d");
1260 add_format_str_info(vcdinfo_get_preparer_id(p_vcd->vcd));
1264 add_format_str_info(vcdinfo_get_publisher_id(p_vcd->vcd));
1268 if ( VCDINFO_ITEM_TYPE_SEGMENT==itemid->type ) {
1269 char seg_type_str[10];
1271 sprintf(seg_type_str, " %s",
1272 vcdinfo_video_type2str(p_vcd->vcd, itemid->num));
1273 strncat(tp, seg_type_str, TEMP_STR_LEN-(tp-temp_str));
1274 tp += strlen(seg_type_str);
1276 saw_control_prefix = false;
1280 add_format_num_info(p_vcd->cur_track, "%d");
1284 add_format_str_info(vcdinfo_get_volumeset_id(p_vcd->vcd));
1288 add_format_str_info(vcdinfo_get_volume_id(p_vcd->vcd));
1293 *tp++ = format_str[i];
1294 saw_control_prefix = false;
1297 return strdup(temp_str);
1301 VCDCreatePlayListItem(const input_thread_t *p_input,
1302 thread_vcd_data_t *p_vcd,
1303 playlist_t *p_playlist,
1304 const vcdinfo_itemid_t *itemid,
1305 char *psz_mrl, int psz_mrl_max,
1306 const char *psz_source, int playlist_operation,
1313 switch(itemid->type) {
1314 case VCDINFO_ITEM_TYPE_TRACK:
1317 case VCDINFO_ITEM_TYPE_SEGMENT:
1320 case VCDINFO_ITEM_TYPE_LID:
1323 case VCDINFO_ITEM_TYPE_ENTRY:
1331 snprintf(psz_mrl, psz_mrl_max, "%s%s@%c%u", VCD_MRL_PREFIX, psz_source,
1332 c_type, itemid->num);
1335 VCDFormatStr( p_input, p_vcd,
1336 config_GetPsz( p_input, MODULE_STRING "-title-format" ),
1339 playlist_Add( p_playlist, psz_mrl, p_title, playlist_operation, i_pos );
1342 VCDFormatStr( p_input, p_vcd,
1343 config_GetPsz( p_input, MODULE_STRING "-author-format" ),
1346 if( i_pos == PLAYLIST_END ) i_pos = p_playlist->i_size - 1;
1347 playlist_AddInfo(p_playlist, i_pos, _("General"), _("Author"), "%s",
1352 VCDFixupPlayList( input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1353 const char *psz_source, vcdinfo_itemid_t *itemid,
1354 bool play_single_item )
1357 playlist_t * p_playlist;
1359 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) +
1360 strlen("@T") + strlen("100") + 1;
1362 psz_mrl = malloc( psz_mrl_max );
1364 if( psz_mrl == NULL )
1366 msg_Warn( p_input, "out of memory" );
1370 p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1374 msg_Warn( p_input, "can't find playlist" );
1379 InformationCreate( p_input );
1381 if ( play_single_item )
1383 /* May fill out more information when the playlist user interface becomes
1386 VCDCreatePlayListItem(p_input, p_vcd, p_playlist, itemid,
1387 psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE,
1388 p_playlist->i_index);
1393 vcdinfo_itemid_t list_itemid;
1394 list_itemid.type=VCDINFO_ITEM_TYPE_ENTRY;
1396 playlist_Delete( p_playlist, p_playlist->i_index);
1398 for( i = 0 ; i < p_vcd->num_entries ; i++ )
1401 VCDCreatePlayListItem(p_input, p_vcd, p_playlist, &list_itemid,
1402 psz_mrl, psz_mrl_max, psz_source,
1403 PLAYLIST_APPEND, PLAYLIST_END);
1406 playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
1410 vlc_object_release( p_playlist );
1415 /*****************************************************************************
1417 *****************************************************************************/
1419 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
1420 vlc_value_t oldval, vlc_value_t val, void *p_data )
1422 thread_vcd_data_t *p_vcd;
1424 if (NULL == p_vcd_input) return VLC_EGENERIC;
1426 p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1428 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
1429 msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
1430 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
1432 p_vcd->i_debug = val.i_int;
1436 /*****************************************************************************
1438 read in meta-information about VCD: the number of tracks, segments,
1439 entries, size and starting information. Then set up state variables so
1440 that we read/seek starting at the location specified.
1442 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
1443 and VLC_EGENERIC for some other error.
1444 *****************************************************************************/
1446 E_(Open) ( vlc_object_t *p_this )
1448 input_thread_t * p_input = (input_thread_t *)p_this;
1449 thread_vcd_data_t * p_vcd;
1451 vcdinfo_itemid_t itemid;
1453 bool play_single_item = false;
1455 p_input->pf_read = VCDRead;
1456 p_input->pf_seek = VCDSeek;
1457 p_input->pf_set_area = VCDSetArea;
1458 p_input->pf_set_program = VCDSetProgram;
1460 p_vcd = malloc( sizeof(thread_vcd_data_t) );
1464 LOG_ERR ("out of memory" );
1468 p_input->p_access_data = (void *)p_vcd;
1469 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
1470 p_vcd->in_still = false;
1471 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
1473 /* Set where to log errors messages from libcdio. */
1474 p_vcd_input = (input_thread_t *)p_this;
1475 cdio_log_set_handler ( cdio_log_handler );
1476 vcd_log_set_handler ( vcd_log_handler );
1478 psz_source = VCDParse( p_input, &itemid, &play_single_item );
1480 if ( NULL == psz_source )
1483 return( VLC_EGENERIC );
1486 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1487 psz_source, p_input->psz_name );
1489 p_vcd->p_segments = NULL;
1490 p_vcd->p_entries = NULL;
1493 p_input->i_mtu = VCD_DATA_ONCE;
1495 vlc_mutex_lock( &p_input->stream.stream_lock );
1497 /* If we are here we can control the pace... */
1498 p_input->stream.b_pace_control = 1;
1500 p_input->stream.b_seekable = 1;
1501 p_input->stream.p_selected_area->i_size = 0;
1502 p_input->stream.p_selected_area->i_tell = 0;
1504 vlc_mutex_unlock( &p_input->stream.stream_lock );
1506 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1508 msg_Warn( p_input, "could not open %s", psz_source );
1512 p_vcd->b_svd= vcdinfo_get_tracksSVD(p_vcd->vcd);;
1514 /* Get track information. */
1515 p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
1516 vcdinfo_get_cd_image(p_vcd->vcd),
1517 &p_vcd->p_sectors );
1518 if( p_vcd->num_tracks < 0 )
1519 LOG_ERR ("unable to count tracks" );
1520 else if( p_vcd->num_tracks <= 1 )
1521 LOG_ERR ("no movie tracks found" );
1522 if( p_vcd->num_tracks <= 1)
1524 vcdinfo_close( p_vcd->vcd );
1528 /* Set stream and area data */
1529 vlc_mutex_lock( &p_input->stream.stream_lock );
1531 /* Initialize ES structures */
1532 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
1534 /* disc input method */
1535 p_input->stream.i_method = INPUT_METHOD_VCD;
1537 p_input->stream.i_area_nb = 1;
1540 /* Initialize segment information. */
1541 VCDSegments( p_input );
1543 /* Initialize track area information. */
1544 VCDTracks( p_input );
1546 if( VCDEntryPoints( p_input ) < 0 )
1548 msg_Warn( p_input, "could not read entry points, will not use them" );
1549 p_vcd->b_valid_ep = false;
1552 if( VCDLIDs( p_input ) < 0 )
1554 msg_Warn( p_input, "could not read entry LIDs" );
1557 b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
1559 vlc_mutex_unlock( &p_input->stream.stream_lock );
1561 if ( ! b_play_ok ) {
1562 vcdinfo_close( p_vcd->vcd );
1566 if( !p_input->psz_demux || !*p_input->psz_demux )
1569 p_input->psz_demux = "vcdx";
1571 p_input->psz_demux = "ps";
1575 p_vcd->p_intf = intf_Create( p_input, "vcdx" );
1576 p_vcd->p_intf->b_block = VLC_FALSE;
1577 intf_RunThread( p_vcd->p_intf );
1579 if (play_single_item)
1580 VCDFixupPlayList( p_input, p_vcd, psz_source, &itemid, play_single_item );
1588 return VLC_EGENERIC;
1591 /*****************************************************************************
1592 * Close: closes VCD releasing allocated memory.
1593 *****************************************************************************/
1595 E_(Close) ( vlc_object_t *p_this )
1597 input_thread_t * p_input = (input_thread_t *)p_this;
1598 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
1600 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1601 vcdinfo_close( p_vcd->vcd );
1603 free( p_vcd->p_entries );
1604 free( p_vcd->p_segments );
1605 free( p_vcd->p_sectors );
1607 /* For reasons that are a mystery to me we don't have to deal with
1608 stopping, and destroying the p_vcd->p_intf thread. And if we do
1609 it causes problems upstream.
1611 if( p_vcd->p_intf != NULL )
1613 p_vcd->p_intf = NULL;
1617 p_input->p_access_data = NULL;