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
7 * $Id: access.c,v 1.16 2004/01/06 04:10:18 rocky Exp $
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 *varname, const char *label );
81 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
83 /****************************************************************************
85 ****************************************************************************/
87 /* FIXME: This variable is a hack. Would be nice to eliminate the
90 static input_thread_t *p_vcd_input = NULL;
92 /* process messages that originate from libcdio. */
94 cdio_log_handler (cdio_log_level_t level, const char message[])
96 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
100 if (p_vcd->i_debug & INPUT_DBG_CDIO)
101 msg_Dbg( p_vcd_input, message);
104 msg_Warn( p_vcd_input, message);
107 case CDIO_LOG_ASSERT:
108 msg_Err( p_vcd_input, message);
111 msg_Warn( p_vcd_input, message,
112 _("The above message had unknown log level"),
118 /* process messages that originate from vcdinfo. */
120 vcd_log_handler (vcd_log_level_t level, const char message[])
122 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
126 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
127 msg_Dbg( p_vcd_input, message);
130 msg_Warn( p_vcd_input, message);
134 msg_Err( p_vcd_input, message);
137 msg_Warn( p_vcd_input, "%s\n%s %d", message,
138 _("The above message had unknown vcdimager log level"),
144 /*****************************************************************************
145 * VCDRead: reads i_len bytes from the VCD into p_buffer.
146 *****************************************************************************
147 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
149 *****************************************************************************/
151 VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
153 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
157 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
161 dbg_print( (INPUT_DBG_CALL), "lsn: %u", p_vcd->cur_lsn );
163 /* Compute the number of blocks we have to read */
165 i_blocks = i_len / M2F2_SECTOR_SIZE;
167 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
170 if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
171 vcdplayer_read_status_t read_status;
173 /* We've run off of the end of this entry. Do we continue or stop? */
174 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
175 "end reached, cur: %u", p_vcd->cur_lsn );
177 read_status = vcdplayer_pbc_is_on( p_vcd )
178 ? vcdplayer_pbc_nav( p_input )
179 : vcdplayer_non_pbc_nav( p_input );
181 switch (read_status) {
183 /* End reached. Return NULL to indicated this. */
185 /* Some sort of error. */
188 case READ_STILL_FRAME:
190 /* Reached the end of a still frame. */
192 byte_t * p_buf = p_buffer;
193 pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;;
195 p_buf += (i_index*M2F2_SECTOR_SIZE);
196 memset(p_buf, 0, M2F2_SECTOR_SIZE);
199 dbg_print(INPUT_DBG_STILL, "Handled still event");
202 p_vcd->p_intf->p_sys->b_still = 1;
203 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
206 vlc_mutex_lock( &p_input->stream.stream_lock );
208 p_pgrm = p_input->stream.p_selected_program;
209 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
211 vlc_mutex_unlock( &p_input->stream.stream_lock );
213 input_ClockManageControl( p_input, p_pgrm, 0 );
215 p_vcd->p_intf->p_sys->b_still = 1;
216 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
218 return i_read + M2F2_SECTOR_SIZE;
226 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
228 p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
230 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
237 if( p_vcd->b_valid_ep &&
238 /* FIXME kludge so that read does not update chapter
239 * when a manual chapter change was requested and not
240 * yet accomplished */
241 !p_input->stream.p_new_area )
243 unsigned int i_entry = p_input->stream.p_selected_area->i_part;
245 vlc_mutex_lock( &p_input->stream.stream_lock );
247 if( i_entry < p_vcd->num_entries &&
248 p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
250 dbg_print( INPUT_DBG_PBC,
251 "new entry, i_entry %d, sector %d, es %d",
252 i_entry, p_vcd->cur_lsn,
253 p_vcd->p_entries[i_entry] );
254 p_vcd->play_item.num =
255 ++ p_input->stream.p_selected_area->i_part;
256 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
257 VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
258 "chapter", "Setting entry" );
260 vlc_mutex_unlock( &p_input->stream.stream_lock );
263 i_read += M2F2_SECTOR_SIZE;
266 if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
268 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
269 p_vcd->cur_lsn, p_last_sector ) < 0 )
271 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
275 p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
276 p_last_sector, i_len % M2F2_SECTOR_SIZE );
277 i_read += i_len % M2F2_SECTOR_SIZE;
284 /*****************************************************************************
285 * VCDSetProgram: Does nothing since a VCD is mono_program
286 *****************************************************************************/
288 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
290 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
291 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
296 /*****************************************************************************
297 * VCDSetArea: initialize internal data structures and input stream data
298 so set subsequent reading and seeking to reflect that we are
299 at track x, entry or segment y.
300 This is called for each user navigation request, e.g. the GUI
301 Chapter/Title selections or in initial MRL parsing.
302 ****************************************************************************/
304 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
306 thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
307 unsigned int i_entry = p_area->i_part;
308 track_t i_track = p_area->i_id;
309 int old_seekable = p_input->stream.b_seekable;
310 unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb;
312 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
313 "track: %d, entry %d, seekable %d, area %lx, select area %lx ",
314 i_track, i_entry, old_seekable,
315 (long unsigned int) p_area,
316 (long unsigned int) p_input->stream.p_selected_area );
318 /* we can't use the interface slider until initilization is complete */
319 p_input->stream.b_seekable = 0;
321 if( p_area != p_input->stream.p_selected_area )
325 /* If is the result of a track change, make the entry valid. */
326 if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
327 i_entry = p_area->i_plugin_data;
329 /* Change the default area */
330 p_input->stream.p_selected_area = p_area;
332 /* Update the navigation variables without triggering a callback */
334 VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
337 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
338 for( i = p_area->i_plugin_data; i < i_nb; i++ )
340 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
341 "chapter", "Adding entry choice");
345 unsigned int audio_type =
346 vcdinfo_get_track_audio_type(p_vcd->vcd, i_track);
347 unsigned int i_channels =
348 vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type);
350 var_Change( p_input, "audio_channels", VLC_VAR_CLEARCHOICES, NULL,
353 for( i = 0; i < i_channels; i++ )
355 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
356 "audio_channels", "Adding audio choice");
363 VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
364 p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
367 VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
368 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
369 p_vcd->p_sectors[i_track+1],
372 p_input->stream.b_seekable = old_seekable;
373 /* warn interface that something has changed */
374 p_input->stream.b_changed = 1;
380 /****************************************************************************
382 ****************************************************************************/
384 VCDSeek( input_thread_t * p_input, off_t i_off )
386 thread_vcd_data_t * p_vcd;
387 unsigned int i_entry=0; /* invalid entry */
389 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
391 p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
393 vlc_mutex_lock( &p_input->stream.stream_lock );
394 #define p_area p_input->stream.p_selected_area
396 if( p_vcd->b_valid_ep )
398 for( i_entry = 0 ; i_entry < p_vcd->num_entries ; i_entry ++ )
400 if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
402 VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
403 "chapter", "Setting entry" );
407 p_vcd->play_item.num = p_area->i_part = i_entry;
408 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
412 p_input->stream.p_selected_area->i_tell = i_off;
414 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
415 "orig %d, cur: %d, offset: %lld, start: %lld, entry %d",
416 p_vcd->origin_lsn, p_vcd->cur_lsn, i_off,
417 p_input->stream.p_selected_area->i_start, i_entry );
419 vlc_mutex_unlock( &p_input->stream.stream_lock );
422 /*****************************************************************************
423 VCDPlay: set up internal structures so seeking/reading places an item.
424 itemid: the thing to play.
425 user_entry: true if itemid is a user selection (rather than internally-
426 generated selection such as via PBC) in which case we may have to adjust
427 for differences in numbering.
428 *****************************************************************************/
430 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
432 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
433 input_area_t * p_area;
435 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
436 itemid.num, itemid.type);
438 if (!p_input->p_access_data) return VLC_EGENERIC;
440 p_vcd->in_still = false;
441 p_vcd->cur_lid = VCDINFO_INVALID_LID;
443 #define area p_input->stream.pp_areas
445 switch (itemid.type) {
446 case VCDINFO_ITEM_TYPE_TRACK:
448 /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
451 if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
452 LOG_ERR ("Invalid track number %d", itemid.num );
455 p_area = area[itemid.num];
456 p_area->i_part = p_area->i_plugin_data;
457 p_input->stream.b_seekable = 1;
459 case VCDINFO_ITEM_TYPE_SEGMENT:
460 /* Valid segments go from 0...num_segments-1. */
461 if (itemid.num >= p_vcd->num_segments) {
462 LOG_ERR ( "Invalid segment number: %d", itemid.num );
465 vcdinfo_video_segment_type_t segtype =
466 vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
468 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
469 vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
470 (int) segtype, itemid.num);
473 p_area->i_part = itemid.num;
477 case VCDINFO_FILES_VIDEO_NTSC_STILL:
478 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
479 case VCDINFO_FILES_VIDEO_PAL_STILL:
480 case VCDINFO_FILES_VIDEO_PAL_STILL2:
481 p_input->stream.b_seekable = 0;
482 p_vcd->in_still = true;
485 p_input->stream.b_seekable = 1;
486 p_vcd->in_still = false;
491 case VCDINFO_ITEM_TYPE_LID:
492 /* LIDs go from 1..num_lids. */
493 if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
494 LOG_ERR ( "Invalid LID number: %d", itemid.num );
497 p_vcd->cur_lid = itemid.num;
498 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
500 switch (p_vcd->pxd.descriptor_type) {
502 case PSD_TYPE_SELECTION_LIST:
503 case PSD_TYPE_EXT_SELECTION_LIST: {
504 vcdinfo_itemid_t trans_itemid;
505 uint16_t trans_itemid_num;
507 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
508 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
509 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
510 p_vcd->loop_count = 1;
511 p_vcd->loop_item = trans_itemid;
512 return VCDPlay( p_input, trans_itemid );
516 case PSD_TYPE_PLAY_LIST: {
517 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
519 return vcdplayer_inc_play_item(p_input)
520 ? VLC_SUCCESS : VLC_EGENERIC;
524 case PSD_TYPE_END_LIST:
525 case PSD_TYPE_COMMAND_LIST:
532 case VCDINFO_ITEM_TYPE_ENTRY:
533 /* Entries go from 0..num_entries-1. */
534 if (itemid.num >= p_vcd->num_entries) {
535 LOG_ERR ("Invalid entry number: %d", itemid.num );
538 track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
539 p_area = area[cur_track];
540 p_area->i_part = itemid.num;
541 p_input->stream.b_seekable = 1;
545 LOG_ERR ("unknown entry type" );
549 VCDSetArea( p_input, p_area );
553 p_vcd->play_item = itemid;
555 dbg_print( (INPUT_DBG_CALL),
556 "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d",
557 p_area->i_start, p_area->i_size,
558 p_area->i_tell, p_vcd->cur_lsn );
563 /*****************************************************************************
564 VCDEntryPoints: Reads the information about the entry points on the disc
565 and initializes area information with that.
566 Before calling this track information should have been read in.
567 *****************************************************************************/
569 VCDEntryPoints( input_thread_t * p_input )
571 thread_vcd_data_t * p_vcd;
573 unsigned int i, i_entry_index = 0;
574 unsigned int i_previous_track = CDIO_INVALID_TRACK;
576 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
578 i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
582 p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
584 if( p_vcd->p_entries == NULL )
586 LOG_ERR ("not enough memory for entry points treatment" );
590 p_vcd->num_entries = 0;
592 for( i = 0 ; i < i_nb ; i++ )
594 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
595 if( i_track <= p_input->stream.i_area_nb )
597 p_vcd->p_entries[i] =
598 vcdinfo_get_entry_lsn(p_vcd->vcd, i);
599 p_input->stream.pp_areas[i_track]->i_part_nb ++;
601 /* if this entry belongs to a new track */
602 if( i_track != i_previous_track )
604 /* i_plugin_data is used to store the first entry of the area*/
605 p_input->stream.pp_areas[i_track]->i_plugin_data =
607 i_previous_track = i_track;
608 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
611 p_vcd->num_entries ++;
614 msg_Warn( p_input, "wrong track number found in entry points" );
616 p_vcd->b_valid_ep = true;
620 /*****************************************************************************
621 * VCDSegments: Reads the information about the segments the disc.
622 *****************************************************************************/
624 VCDSegments( input_thread_t * p_input )
626 thread_vcd_data_t * p_vcd;
628 unsigned int num_segments;
631 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
632 num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
634 #define area p_input->stream.pp_areas
636 /* area 0 is reserved for segments. Set Absolute start offset
638 area[0]->i_plugin_data = 0;
639 input_DelArea( p_input, area[0] );
640 input_AddArea( p_input, 0, 0 );
642 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
643 * (off_t)M2F2_SECTOR_SIZE;
644 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
645 * (off_t)M2F2_SECTOR_SIZE;
647 /* Default Segment */
650 /* i_plugin_data is used to store which entry point is the first
651 of the track (area) */
652 area[0]->i_plugin_data = 0;
654 area[0]->i_part_nb = 0;
656 dbg_print( INPUT_DBG_MRL,
657 "area[0] id: %d, i_start: %lld, i_size: %lld",
658 area[0]->i_id, area[0]->i_start, area[0]->i_size );
660 if (num_segments == 0) return 0;
662 /* We have one additional segment allocated so we can get the size
663 by subtracting seg[i+1] - seg[i].
665 p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
666 if( p_vcd->p_segments == NULL )
668 LOG_ERR ("not enough memory for segment treatment" );
672 /* Update the navigation variables without triggering a callback */
673 VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" );
674 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
676 for( i = 0 ; i < num_segments ; i++ )
678 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
679 area[0]->i_part_nb ++;
680 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
681 "chapter", "Adding segment choice");
686 p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
687 vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
692 /*****************************************************************************
693 VCDTracks: initializes area information.
694 Before calling this track information should have been read in.
695 *****************************************************************************/
697 VCDTracks( input_thread_t * p_input )
699 thread_vcd_data_t * p_vcd;
702 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
704 #define area p_input->stream.pp_areas
706 /* We start area addressing for tracks at 1 since the default area 0
707 is reserved for segments */
709 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
711 /* Tracks are Program Chains */
712 input_AddArea( p_input, i, i );
714 /* Absolute start byte offset and byte size */
715 area[i]->i_start = (off_t) p_vcd->p_sectors[i]
716 * (off_t)M2F2_SECTOR_SIZE;
717 area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
718 * (off_t)M2F2_SECTOR_SIZE;
720 /* Current entry being played in track */
723 /* i_plugin_data is used to store which entry point is the first
724 * of the track (area) */
725 area[i]->i_plugin_data = 0;
727 dbg_print( INPUT_DBG_MRL,
728 "area[%d] id: %d, i_start: %lld, i_size: %lld",
729 i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
737 /*****************************************************************************
738 VCDLIDs: Reads the LIST IDs from the LOT.
739 *****************************************************************************/
741 VCDLIDs( input_thread_t * p_input )
743 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
745 p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
746 p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
748 if (vcdinfo_read_psd (p_vcd->vcd)) {
750 vcdinfo_visit_lot (p_vcd->vcd, false);
754 We need to change libvcdinfo to be more robust when there are
755 problems reading the extended PSD. Given that area-highlighting and
756 selection features in the extended PSD haven't been implemented,
757 it's best then to not try to read this at all.
759 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
760 vcdinfo_visit_lot (p_vcd->vcd, true);
764 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
765 "num LIDs=%d", p_vcd->num_lids);
770 /*****************************************************************************
771 * VCDParse: parse command line
772 *****************************************************************************/
774 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid,
775 /*out*/ bool *play_single_item )
777 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
782 if ( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
783 p_itemid->type=VCDINFO_ITEM_TYPE_LID;
785 *play_single_item=false;
787 p_itemid->type=VCDINFO_ITEM_TYPE_ENTRY;
792 /* On Win32 we want the VCD access plugin to be explicitly requested,
793 * we end up with lots of problems otherwise */
794 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
797 if( !p_input->psz_name )
802 psz_parser = psz_source = strdup( p_input->psz_name );
804 /* Parse input string :
805 * [device][@[type][title]] */
806 while( *psz_parser && *psz_parser != '@' )
811 if( *psz_parser == '@' )
813 /* Found the divide between the source name and the
814 type+entry number. */
821 switch(*psz_parser) {
823 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
825 *play_single_item = true;
828 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
830 *play_single_item = false;
833 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
835 *play_single_item = true;
838 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
840 *play_single_item = true;
846 num = strtol( psz_parser, &psz_next, 10 );
847 if ( *psz_parser != '\0' && *psz_next == '\0')
853 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
859 /* No source specified, so figure it out. */
860 if( !p_input->psz_access ) return NULL;
862 psz_source = config_GetPsz( p_input, "vcd" );
864 if( !psz_source || 0==strlen(psz_source) ) {
865 /* Scan for a CD-ROM drive with a VCD in it. */
866 char **cd_drives = cdio_get_devices_with_cap(NULL,
867 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
868 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
870 if (NULL == cd_drives) return NULL;
871 if (cd_drives[0] == NULL) {
872 cdio_free_device_list(cd_drives);
875 psz_source = strdup(cd_drives[0]);
876 cdio_free_device_list(cd_drives);
880 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
881 "source=%s entry=%d type=%d",
882 psz_source, p_itemid->num, p_itemid->type);
888 Set's start origin subsequent seeks/reads
891 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
892 lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
894 thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
896 p_vcd->origin_lsn = origin_lsn;
897 p_vcd->cur_lsn = cur_lsn;
898 p_vcd->end_lsn = end_lsn;
899 p_vcd->cur_track = cur_track;
900 p_vcd->play_item.num = cur_entry;
901 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
903 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
904 "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
905 origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
907 p_input->stream.p_selected_area->i_tell =
908 (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
910 VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
911 "chapter", "Setting entry");
914 /*****************************************************************************
915 * vcd_Open: Opens a VCD device or file and returns an opaque handle
916 *****************************************************************************/
917 static vcdinfo_obj_t *
918 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
920 vcdinfo_obj_t *p_vcdobj;
923 if( !psz_dev ) return NULL;
925 actual_dev=strdup(psz_dev);
926 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
936 /****************************************************************************
937 * VCDReadSector: Read a sector (2324 bytes)
938 ****************************************************************************/
940 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
941 lsn_t cur_lsn, byte_t * p_buffer )
944 uint8_t subheader [8];
945 uint8_t data [M2F2_SECTOR_SIZE];
947 vcdsector_t vcd_sector;
949 if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
950 &vcd_sector, cur_lsn, true)
953 msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
957 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
962 /****************************************************************************
963 Update the "varname" variable to i_num without triggering a callback.
964 ****************************************************************************/
966 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
967 const char *varname, const char *label)
971 if (NULL != p_vcd_input) {
972 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
973 dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
975 var_Change( p_input, varname, i_action, &val, NULL );
980 MetaInfoAddStr(input_thread_t *p_input, input_info_category_t *p_cat,
981 playlist_t *p_playlist, char *title,
984 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
986 dbg_print( INPUT_DBG_META, "field: %s: %s\n", title, str);
987 input_AddInfo( p_cat, title, "%s", str );
988 playlist_AddInfo( p_playlist, -1, p_cat->psz_name, title,
995 MetaInfoAddNum(input_thread_t *p_input, input_info_category_t *p_cat,
996 playlist_t *p_playlist, char *title, int num)
998 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
999 dbg_print( INPUT_DBG_META, "field %s: %d\n", title, num);
1000 input_AddInfo( p_cat, title, "%d", num );
1001 playlist_AddInfo( p_playlist, -1, p_cat->psz_name, title,
1005 #define addstr(title, str) \
1006 MetaInfoAddStr( p_input, p_cat, p_playlist, title, str );
1008 #define addnum(title, num) \
1009 MetaInfoAddNum( p_input, p_cat, p_playlist, title, num );
1011 static void InformationCreate( input_thread_t *p_input )
1013 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1014 unsigned int i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
1015 unsigned int last_entry = 0;
1016 input_info_category_t *p_cat;
1018 playlist_t *p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1021 p_cat = input_InfoCategory( p_input, "General" );
1023 addstr( _("VCD Format"), vcdinfo_get_format_version_str(p_vcd->vcd) );
1024 addstr( _("Album"), vcdinfo_get_album_id(p_vcd->vcd));
1025 addstr( _("Application"), vcdinfo_get_application_id(p_vcd->vcd) );
1026 addstr( _("Preparer"), vcdinfo_get_preparer_id(p_vcd->vcd) );
1027 addnum( _("Vol #"), vcdinfo_get_volume_num(p_vcd->vcd) );
1028 addnum( _("Vol max #"), vcdinfo_get_volume_count(p_vcd->vcd) );
1029 addstr( _("Volume Set"), vcdinfo_get_volumeset_id(p_vcd->vcd) );
1030 addstr( _("Volume"), vcdinfo_get_volume_id(p_vcd->vcd) );
1031 addstr( _("Publisher"), vcdinfo_get_publisher_id(p_vcd->vcd) );
1032 addstr( _("System Id"), vcdinfo_get_system_id(p_vcd->vcd) );
1033 addnum( "LIDs", vcdinfo_get_num_LIDs(p_vcd->vcd) );
1034 addnum( _("Entries"), vcdinfo_get_num_entries(p_vcd->vcd) );
1035 addnum( _("Segments"), vcdinfo_get_num_segments(p_vcd->vcd) );
1036 addnum( _("Tracks"), vcdinfo_get_num_tracks(p_vcd->vcd) );
1038 /* Spit out track information. Could also include MSF info.
1041 #define TITLE_MAX 30
1042 for( i_track = 1 ; i_track < p_vcd->num_tracks ; i_track++ ) {
1043 char track_str[TITLE_MAX];
1044 unsigned int audio_type = vcdinfo_get_track_audio_type(p_vcd->vcd,
1046 snprintf(track_str, TITLE_MAX, "%s%02d", _("Track"), i_track);
1047 p_cat = input_InfoCategory( p_input, track_str );
1050 addnum(_("Audio Channels"),
1051 vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type) );
1054 addnum(_("First Entry Point"), last_entry );
1055 for ( ; last_entry < i_nb
1056 && vcdinfo_get_track(p_vcd->vcd, last_entry) == i_track;
1058 addnum(_("Last Entry Point"), last_entry-1 );
1062 #define add_format_str_info(val) \
1064 const char *str = val; \
1066 if (val != NULL) { \
1069 strncat(tp, str, TEMP_STR_LEN-(tp-temp_str)); \
1072 saw_control_prefix = false; \
1076 #define add_format_num_info(val, fmt) \
1080 sprintf(num_str, fmt, val); \
1081 len=strlen(num_str); \
1083 strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str)); \
1086 saw_control_prefix = false; \
1090 Take a format string and expand escape sequences, that is sequences that
1091 begin with %, with information from the current VCD.
1092 The expanded string is returned. Here is a list of escape sequences:
1094 %A : The album information
1095 %C : The VCD volume count - the number of CD's in the collection.
1096 %c : The VCD volume num - the number of the CD in the collection.
1097 %F : The VCD Format, e.g. VCD 1.0, VCD 1.1, VCD 2.0, or SVCD
1098 %I : The current entry/segment/playback type, e.g. ENTRY, TRACK, SEGMENT...
1099 %L : The playlist ID prefixed with " LID" if it exists
1101 %N : The current number of the %I - a decimal number
1102 %P : The publisher ID
1103 %p : The preparer ID
1104 %S : If we are in a segment (menu), the kind of segment
1105 %T : The track number
1106 %V : The volume set ID
1108 A number between 1 and the volume count.
1112 VCDFormatStr(const input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1113 const char format_str[], const char *mrl,
1114 const vcdinfo_itemid_t *itemid)
1116 #define TEMP_STR_SIZE 256
1117 #define TEMP_STR_LEN (TEMP_STR_SIZE-1)
1118 static char temp_str[TEMP_STR_SIZE];
1120 char * tp = temp_str;
1121 bool saw_control_prefix = false;
1122 size_t format_len = strlen(format_str);
1124 bzero(temp_str, TEMP_STR_SIZE);
1126 for (i=0; i<format_len; i++) {
1128 if (!saw_control_prefix && format_str[i] != '%') {
1129 *tp++ = format_str[i];
1130 saw_control_prefix = false;
1134 switch(format_str[i]) {
1136 if (saw_control_prefix) {
1139 saw_control_prefix = !saw_control_prefix;
1142 add_format_str_info(vcdinfo_strip_trail(vcdinfo_get_album_id(p_vcd->vcd),
1147 add_format_num_info(vcdinfo_get_volume_num(p_vcd->vcd), "%d");
1151 add_format_num_info(vcdinfo_get_volume_count(p_vcd->vcd), "%d");
1155 add_format_str_info(vcdinfo_get_format_version_str(p_vcd->vcd));
1160 switch (itemid->type) {
1161 case VCDINFO_ITEM_TYPE_TRACK:
1162 strncat(tp, _("Track"), TEMP_STR_LEN-(tp-temp_str));
1163 tp += strlen(_("Track"));
1165 case VCDINFO_ITEM_TYPE_ENTRY:
1166 strncat(tp, _("Entry"), TEMP_STR_LEN-(tp-temp_str));
1167 tp += strlen(_("Entry"));
1169 case VCDINFO_ITEM_TYPE_SEGMENT:
1170 strncat(tp, _("Segment"), TEMP_STR_LEN-(tp-temp_str));
1171 tp += strlen(_("Segment"));
1173 case VCDINFO_ITEM_TYPE_LID:
1174 strncat(tp, _("List ID"), TEMP_STR_LEN-(tp-temp_str));
1175 tp += strlen(_("List ID"));
1177 case VCDINFO_ITEM_TYPE_SPAREID2:
1178 strncat(tp, _("Navigation"), TEMP_STR_LEN-(tp-temp_str));
1179 tp += strlen(_("Navigation"));
1185 saw_control_prefix = false;
1190 if (vcdplayer_pbc_is_on(p_vcd)) {
1192 sprintf(num_str, "%s %d", _("List ID"), p_vcd->cur_lid);
1193 strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));
1194 tp += strlen(num_str);
1196 saw_control_prefix = false;
1200 add_format_str_info(mrl);
1204 add_format_num_info(itemid->num, "%d");
1208 add_format_str_info(vcdinfo_get_preparer_id(p_vcd->vcd));
1212 add_format_str_info(vcdinfo_get_publisher_id(p_vcd->vcd));
1216 if ( VCDINFO_ITEM_TYPE_SEGMENT==itemid->type ) {
1217 char seg_type_str[10];
1219 sprintf(seg_type_str, " %s",
1220 vcdinfo_video_type2str(p_vcd->vcd, itemid->num));
1221 strncat(tp, seg_type_str, TEMP_STR_LEN-(tp-temp_str));
1222 tp += strlen(seg_type_str);
1224 saw_control_prefix = false;
1228 add_format_num_info(p_vcd->cur_track, "%d");
1232 add_format_str_info(vcdinfo_get_volumeset_id(p_vcd->vcd));
1236 add_format_str_info(vcdinfo_get_volume_id(p_vcd->vcd));
1241 *tp++ = format_str[i];
1242 saw_control_prefix = false;
1245 return strdup(temp_str);
1249 VCDCreatePlayListItem(const input_thread_t *p_input,
1250 thread_vcd_data_t *p_vcd,
1251 playlist_t *p_playlist,
1252 const vcdinfo_itemid_t *itemid,
1253 char *psz_mrl, int psz_mrl_max,
1254 const char *psz_source, int playlist_operation,
1261 switch(itemid->type) {
1262 case VCDINFO_ITEM_TYPE_TRACK:
1265 case VCDINFO_ITEM_TYPE_SEGMENT:
1268 case VCDINFO_ITEM_TYPE_LID:
1271 case VCDINFO_ITEM_TYPE_ENTRY:
1279 snprintf(psz_mrl, psz_mrl_max, "%s%s@%c%u", VCD_MRL_PREFIX, psz_source,
1280 c_type, itemid->num);
1283 VCDFormatStr( p_input, p_vcd,
1284 config_GetPsz( p_input, MODULE_STRING "-title-format" ),
1287 playlist_Add( p_playlist, psz_mrl, p_title, playlist_operation, i_pos );
1290 VCDFormatStr( p_input, p_vcd,
1291 config_GetPsz( p_input, MODULE_STRING "-author-format" ),
1294 if( i_pos == PLAYLIST_END ) i_pos = p_playlist->i_size - 1;
1295 playlist_AddInfo(p_playlist, i_pos, _("General"), _("Author"), "%s",
1300 VCDFixupPlayList( input_thread_t *p_input, thread_vcd_data_t *p_vcd,
1301 const char *psz_source, vcdinfo_itemid_t *itemid,
1302 bool play_single_item )
1305 playlist_t * p_playlist;
1307 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) +
1308 strlen("@T") + strlen("100") + 1;
1310 psz_mrl = malloc( psz_mrl_max );
1312 if( psz_mrl == NULL )
1314 msg_Warn( p_input, "out of memory" );
1318 p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
1322 msg_Warn( p_input, "can't find playlist" );
1327 InformationCreate( p_input );
1329 if ( play_single_item )
1331 /* May fill out more information when the playlist user interface becomes
1334 VCDCreatePlayListItem(p_input, p_vcd, p_playlist, itemid,
1335 psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE,
1336 p_playlist->i_index);
1341 vcdinfo_itemid_t list_itemid;
1342 list_itemid.type=VCDINFO_ITEM_TYPE_ENTRY;
1344 playlist_Delete( p_playlist, p_playlist->i_index);
1346 for( i = 0 ; i < p_vcd->num_entries ; i++ )
1349 VCDCreatePlayListItem(p_input, p_vcd, p_playlist, &list_itemid,
1350 psz_mrl, psz_mrl_max, psz_source,
1351 PLAYLIST_APPEND, PLAYLIST_END);
1354 playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
1358 vlc_object_release( p_playlist );
1363 /*****************************************************************************
1365 *****************************************************************************/
1367 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
1368 vlc_value_t oldval, vlc_value_t val, void *p_data )
1370 thread_vcd_data_t *p_vcd;
1372 if (NULL == p_vcd_input) return VLC_EGENERIC;
1374 p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1376 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
1377 msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
1378 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
1380 p_vcd->i_debug = val.i_int;
1384 /*****************************************************************************
1386 read in meta-information about VCD: the number of tracks, segments,
1387 entries, size and starting information. Then set up state variables so
1388 that we read/seek starting at the location specified.
1390 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
1391 and VLC_EGENERIC for some other error.
1392 *****************************************************************************/
1394 E_(Open) ( vlc_object_t *p_this )
1396 input_thread_t * p_input = (input_thread_t *)p_this;
1397 thread_vcd_data_t * p_vcd;
1399 vcdinfo_itemid_t itemid;
1401 bool play_single_item = false;
1403 p_input->pf_read = VCDRead;
1404 p_input->pf_seek = VCDSeek;
1405 p_input->pf_set_area = VCDSetArea;
1406 p_input->pf_set_program = VCDSetProgram;
1408 p_vcd = malloc( sizeof(thread_vcd_data_t) );
1412 LOG_ERR ("out of memory" );
1416 p_input->p_access_data = (void *)p_vcd;
1417 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
1419 /* Set where to log errors messages from libcdio. */
1420 p_vcd_input = (input_thread_t *)p_this;
1421 cdio_log_set_handler ( cdio_log_handler );
1422 vcd_log_set_handler ( vcd_log_handler );
1424 psz_source = VCDParse( p_input, &itemid, &play_single_item );
1426 if ( NULL == psz_source )
1429 return( VLC_EGENERIC );
1432 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1433 psz_source, p_input->psz_name );
1435 p_vcd->p_segments = NULL;
1436 p_vcd->p_entries = NULL;
1439 p_input->i_mtu = VCD_DATA_ONCE;
1441 vlc_mutex_lock( &p_input->stream.stream_lock );
1443 /* If we are here we can control the pace... */
1444 p_input->stream.b_pace_control = 1;
1446 p_input->stream.b_seekable = 1;
1447 p_input->stream.p_selected_area->i_size = 0;
1448 p_input->stream.p_selected_area->i_tell = 0;
1450 vlc_mutex_unlock( &p_input->stream.stream_lock );
1452 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1454 msg_Warn( p_input, "could not open %s", psz_source );
1458 p_vcd->b_svd= vcdinfo_get_tracksSVD(p_vcd->vcd);;
1460 /* Get track information. */
1461 p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
1462 vcdinfo_get_cd_image(p_vcd->vcd),
1463 &p_vcd->p_sectors );
1464 if( p_vcd->num_tracks < 0 )
1465 LOG_ERR ("unable to count tracks" );
1466 else if( p_vcd->num_tracks <= 1 )
1467 LOG_ERR ("no movie tracks found" );
1468 if( p_vcd->num_tracks <= 1)
1470 vcdinfo_close( p_vcd->vcd );
1474 /* Set stream and area data */
1475 vlc_mutex_lock( &p_input->stream.stream_lock );
1477 /* Initialize ES structures */
1478 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
1480 /* disc input method */
1481 p_input->stream.i_method = INPUT_METHOD_VCD;
1483 p_input->stream.i_area_nb = 1;
1486 /* Initialize segment information. */
1487 VCDSegments( p_input );
1489 /* Initialize track area information. */
1490 VCDTracks( p_input );
1492 if( VCDEntryPoints( p_input ) < 0 )
1494 msg_Warn( p_input, "could not read entry points, will not use them" );
1495 p_vcd->b_valid_ep = false;
1498 if( VCDLIDs( p_input ) < 0 )
1500 msg_Warn( p_input, "could not read entry LIDs" );
1503 b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
1505 vlc_mutex_unlock( &p_input->stream.stream_lock );
1507 if ( ! b_play_ok ) {
1508 vcdinfo_close( p_vcd->vcd );
1512 if( !p_input->psz_demux || !*p_input->psz_demux )
1515 p_input->psz_demux = "vcdx";
1517 p_input->psz_demux = "ps";
1521 p_vcd->p_intf = intf_Create( p_input, "vcdx" );
1522 p_vcd->p_intf->b_block = VLC_FALSE;
1523 intf_RunThread( p_vcd->p_intf );
1525 VCDFixupPlayList( p_input, p_vcd, psz_source, &itemid, play_single_item );
1533 return VLC_EGENERIC;
1536 /*****************************************************************************
1537 * Close: closes VCD releasing allocated memory.
1538 *****************************************************************************/
1540 E_(Close) ( vlc_object_t *p_this )
1542 input_thread_t * p_input = (input_thread_t *)p_this;
1543 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
1545 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1546 vcdinfo_close( p_vcd->vcd );
1548 free( p_vcd->p_entries );
1549 free( p_vcd->p_segments );
1551 /* For reasons that are a mystery to me we don't have to deal with
1552 stopping, and destroying the p_vcd->p_intf thread. And if we do
1553 it causes problems upstream.
1555 if( p_vcd->p_intf != NULL )
1557 p_vcd->p_intf = NULL;
1561 p_input->p_access_data = NULL;