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 VideoLAN
7 * $Id: vcd.c,v 1.5 2003/11/20 02:15:37 rocky Exp $
9 * Authors: Johan Bilien <jobi@via.ecp.fr>
10 * Rocky Bernstein <rocky@panix.com>
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>
33 #include <vlc_interface.h>
35 #include "../../demux/mpeg/system.h"
38 #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 /*****************************************************************************
55 *****************************************************************************/
57 /* First those which are accessed from outside (via pointers). */
58 static int VCDOpen ( vlc_object_t * );
59 static void VCDClose ( vlc_object_t * );
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 );
77 static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action,
78 const char *varname, const char *label );
80 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
82 static int debug_callback ( vlc_object_t *p_this, const char *psz_name,
83 vlc_value_t oldval, vlc_value_t val,
86 #define DEBUG_TEXT N_("set debug mask for additional debugging.")
87 #define DEBUG_LONGTEXT N_( \
88 "This integer when viewed in binary is a debugging mask\n" \
97 "vcdinfo (100) 256\n" )
99 /*****************************************************************************
100 * Exported prototypes
101 *****************************************************************************/
102 int E_(VCDOpen) ( vlc_object_t * );
103 void E_(VCDClose) ( vlc_object_t * );
104 int E_(VCDOpenIntf) ( vlc_object_t * );
105 void E_(VCDCloseIntf) ( vlc_object_t * );
106 int E_(InitVCD) ( vlc_object_t * );
107 void E_(EndVCD) ( vlc_object_t * );
109 /*****************************************************************************
111 *****************************************************************************/
113 add_usage_hint( N_("vcdx:[device-or-file][@{P,S,T}num]") );
114 set_description( _("Video CD (VCD 1.0, 1.1, 2.0, SVCD, HQVCD) input") );
115 set_capability( "access", 85 /* slightly higher than vcd */ );
116 set_callbacks( E_(VCDOpen), E_(VCDClose) );
117 add_shortcut( "vcd" );
118 add_shortcut( "vcdx" );
120 /* Configuration options */
121 add_category_hint( N_("VCDX"), NULL, VLC_TRUE );
122 add_integer ( MODULE_STRING "-debug", 0, debug_callback, DEBUG_TEXT,
123 DEBUG_LONGTEXT, VLC_TRUE );
127 set_capability( "demux", 0 );
128 set_callbacks( E_(InitVCD), E_(EndVCD) );
132 set_capability( "interface", 0 );
133 set_callbacks( E_(VCDOpenIntf), E_(VCDCloseIntf) );
136 /****************************************************************************
138 ****************************************************************************/
139 /* FIXME: This variable is a hack. Would be nice to eliminate. */
140 static input_thread_t *p_vcd_input = NULL;
143 debug_callback ( vlc_object_t *p_this, const char *psz_name,
144 vlc_value_t oldval, vlc_value_t val, void *p_data )
146 thread_vcd_data_t *p_vcd;
148 if (NULL == p_vcd_input) return VLC_EGENERIC;
150 p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
152 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
153 msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
154 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
156 p_vcd->i_debug = val.i_int;
160 /* process messages that originate from libcdio. */
162 cdio_log_handler (cdio_log_level_t level, const char message[])
164 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
168 if (p_vcd->i_debug & INPUT_DBG_CDIO)
169 msg_Dbg( p_vcd_input, message);
172 msg_Warn( p_vcd_input, message);
175 case CDIO_LOG_ASSERT:
176 msg_Err( p_vcd_input, message);
179 msg_Warn( p_vcd_input, message,
180 _("The above message had unknown vcdimager log level"),
186 /* process messages that originate from vcdinfo. */
188 vcd_log_handler (vcd_log_level_t level, const char message[])
190 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
194 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
195 msg_Dbg( p_vcd_input, message);
198 msg_Warn( p_vcd_input, message);
202 msg_Err( p_vcd_input, message);
205 msg_Warn( p_vcd_input, "%s\n%s %d", message,
206 _("The above message had unknown vcdimager log level"),
213 * Data reading functions
216 /*****************************************************************************
218 read in meta-information about VCD: the number of tracks, segments,
219 entries, size and starting information. Then set up state variables so
220 that we read/seek starting at the location specified.
222 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
223 and VLC_EGENERIC for some other error.
224 *****************************************************************************/
226 VCDOpen( vlc_object_t *p_this )
228 input_thread_t * p_input = (input_thread_t *)p_this;
229 thread_vcd_data_t * p_vcd;
231 vcdinfo_itemid_t itemid;
234 p_input->pf_read = VCDRead;
235 p_input->pf_seek = VCDSeek;
236 p_input->pf_set_area = VCDSetArea;
237 p_input->pf_set_program = VCDSetProgram;
239 p_vcd = malloc( sizeof(thread_vcd_data_t) );
243 LOG_ERR ("out of memory" );
247 p_input->p_access_data = (void *)p_vcd;
248 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
249 psz_source = VCDParse( p_input, &itemid );
251 if ( NULL == psz_source )
254 return( VLC_EGENERIC );
257 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
259 p_vcd->p_segments = NULL;
260 p_vcd->p_entries = NULL;
263 p_input->i_mtu = VCD_DATA_ONCE;
265 vlc_mutex_lock( &p_input->stream.stream_lock );
267 /* If we are here we can control the pace... */
268 p_input->stream.b_pace_control = 1;
270 p_input->stream.b_seekable = 1;
271 p_input->stream.p_selected_area->i_size = 0;
272 p_input->stream.p_selected_area->i_tell = 0;
274 vlc_mutex_unlock( &p_input->stream.stream_lock );
276 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
278 msg_Warn( p_input, "could not open %s", psz_source );
284 /* Get track information. */
285 p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
286 vcdinfo_get_cd_image(p_vcd->vcd),
289 if( p_vcd->num_tracks < 0 )
290 LOG_ERR ("unable to count tracks" );
291 else if( p_vcd->num_tracks <= 1 )
292 LOG_ERR ("no movie tracks found" );
293 if( p_vcd->num_tracks <= 1)
295 vcdinfo_close( p_vcd->vcd );
300 /* Set stream and area data */
301 vlc_mutex_lock( &p_input->stream.stream_lock );
303 /* Initialize ES structures */
304 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
306 /* disc input method */
307 p_input->stream.i_method = INPUT_METHOD_VCD;
309 p_input->stream.i_area_nb = 1;
312 /* Initialize segment information. */
313 VCDSegments( p_input );
315 /* Initialize track area information. */
316 VCDTracks( p_input );
318 if( VCDEntryPoints( p_input ) < 0 )
320 msg_Warn( p_input, "could not read entry points, will not use them" );
321 p_vcd->b_valid_ep = false;
324 if( VCDLIDs( p_input ) < 0 )
326 msg_Warn( p_input, "could not read entry LIDs" );
329 b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
331 vlc_mutex_unlock( &p_input->stream.stream_lock );
334 vcdinfo_close( p_vcd->vcd );
339 if( !p_input->psz_demux || !*p_input->psz_demux )
342 p_input->psz_demux = "vcdx";
344 p_input->psz_demux = "ps";
348 p_vcd->p_intf = intf_Create( p_input, "vcdx" );
349 p_vcd->p_intf->b_block = VLC_FALSE;
350 intf_RunThread( p_vcd->p_intf );
355 /*****************************************************************************
356 * VCDClose: closes VCD releasing allocated memory.
357 *****************************************************************************/
359 VCDClose( vlc_object_t *p_this )
361 input_thread_t * p_input = (input_thread_t *)p_this;
362 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
364 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
365 vcdinfo_close( p_vcd->vcd );
367 free( p_vcd->p_entries );
368 free( p_vcd->p_segments );
370 /* For reasons that are a mystery to me we don't have to deal with
371 stopping, and destroying the p_vcd->p_intf thread. And if we do
372 it causes problems upstream.
374 if( p_vcd->p_intf != NULL )
376 p_vcd->p_intf = NULL;
380 p_input->p_access_data = NULL;
384 /*****************************************************************************
385 * VCDRead: reads i_len bytes from the VCD into p_buffer.
386 *****************************************************************************
387 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
389 *****************************************************************************/
391 VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
393 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
397 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
401 dbg_print( (INPUT_DBG_CALL), "lsn: %u", p_vcd->cur_lsn );
403 /* Compute the number of blocks we have to read */
405 i_blocks = i_len / M2F2_SECTOR_SIZE;
407 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
410 if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
411 vcdplayer_read_status_t read_status;
413 /* We've run off of the end of this entry. Do we continue or stop? */
414 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
415 "end reached, cur: %u", p_vcd->cur_lsn );
417 read_status = vcdplayer_pbc_is_on( p_vcd )
418 ? vcdplayer_pbc_nav( p_input )
419 : vcdplayer_non_pbc_nav( p_input );
421 switch (read_status) {
423 /* End reached. Return NULL to indicated this. */
425 /* Some sort of error. */
428 case READ_STILL_FRAME:
430 /* Reached the end of a still frame. */
432 byte_t * p_buf = p_buffer;
433 pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;;
435 p_buf += (i_index*M2F2_SECTOR_SIZE);
436 memset(p_buf, 0, M2F2_SECTOR_SIZE);
439 dbg_print(INPUT_DBG_STILL, "Handled still event\n");
441 /* p_vcd->p_intf->b_end_of_cell = true; */
442 input_SetStatus( p_input, INPUT_STATUS_PAUSE );
444 vlc_mutex_lock( &p_input->stream.stream_lock );
446 p_pgrm = p_input->stream.p_selected_program;
447 p_pgrm->i_synchro_state = SYNCHRO_REINIT;
449 vlc_mutex_unlock( &p_input->stream.stream_lock );
451 input_ClockManageControl( p_input, p_pgrm, 0 );
453 return i_read + M2F2_SECTOR_SIZE;
461 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
463 p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
465 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
472 if( p_vcd->b_valid_ep &&
473 /* FIXME kludge so that read does not update chapter
474 * when a manual chapter change was requested and not
475 * yet accomplished */
476 !p_input->stream.p_new_area )
478 unsigned int i_entry = p_input->stream.p_selected_area->i_part;
480 vlc_mutex_lock( &p_input->stream.stream_lock );
482 if( i_entry < p_vcd->num_entries &&
483 p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
485 dbg_print( INPUT_DBG_PBC,
486 "new entry, i_entry %d, sector %d, es %d",
487 i_entry, p_vcd->cur_lsn,
488 p_vcd->p_entries[i_entry] );
489 p_vcd->play_item.num =
490 ++ p_input->stream.p_selected_area->i_part;
491 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
492 VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
493 "chapter", "Setting entry" );
495 vlc_mutex_unlock( &p_input->stream.stream_lock );
498 i_read += M2F2_SECTOR_SIZE;
501 if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
503 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
504 p_vcd->cur_lsn, p_last_sector ) < 0 )
506 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
510 p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
511 p_last_sector, i_len % M2F2_SECTOR_SIZE );
512 i_read += i_len % M2F2_SECTOR_SIZE;
519 /*****************************************************************************
520 * VCDSetProgram: Does nothing since a VCD is mono_program
521 *****************************************************************************/
523 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
525 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
526 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
531 /*****************************************************************************
532 * VCDSetArea: initialize internal data structures and input stream data
533 so set subsequent reading and seeking to reflect that we are
534 at track x, entry or segment y.
535 This is called for each user navigation request, e.g. the GUI
536 Chapter/Title selections or in initial MRL parsing.
537 ****************************************************************************/
539 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
541 thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
542 unsigned int i_entry = p_area->i_part;
543 track_t i_track = p_area->i_id;
544 int old_seekable = p_input->stream.b_seekable;
545 unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb;
547 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
548 "track: %d, entry %d, seekable %d, area %lx, select area %lx ",
549 i_track, i_entry, old_seekable,
550 (long unsigned int) p_area,
551 (long unsigned int) p_input->stream.p_selected_area );
553 /* we can't use the interface slider until initilization is complete */
554 p_input->stream.b_seekable = 0;
556 if( p_area != p_input->stream.p_selected_area )
560 /* If is the result of a track change, make the entry valid. */
561 if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
562 i_entry = p_area->i_plugin_data;
564 /* Change the default area */
565 p_input->stream.p_selected_area = p_area;
567 /* Update the navigation variables without triggering a callback */
568 VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
571 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
572 for( i = p_area->i_plugin_data; i < i_nb; i++ )
574 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
575 "chapter", "Adding entry choice");
580 VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
581 p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
584 VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
585 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
586 p_vcd->p_sectors[i_track+1],
589 p_input->stream.b_seekable = old_seekable;
590 /* warn interface that something has changed */
591 p_input->stream.b_changed = 1;
597 /****************************************************************************
599 ****************************************************************************/
601 VCDSeek( input_thread_t * p_input, off_t i_off )
603 thread_vcd_data_t * p_vcd;
604 unsigned int i_entry=0; /* invalid entry */
606 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
608 p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
610 vlc_mutex_lock( &p_input->stream.stream_lock );
611 #define p_area p_input->stream.p_selected_area
613 if( p_vcd->b_valid_ep )
615 for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ )
617 if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
619 VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
620 "chapter", "Setting entry" );
624 p_vcd->play_item.num = p_area->i_part = i_entry;
625 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
629 p_input->stream.p_selected_area->i_tell = i_off;
631 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
632 "orig %d, cur: %d, offset: %lld, start: %lld, entry %d",
633 p_vcd->origin_lsn, p_vcd->cur_lsn, i_off,
634 p_input->stream.p_selected_area->i_start, i_entry );
636 vlc_mutex_unlock( &p_input->stream.stream_lock );
639 /*****************************************************************************
640 VCDPlay: set up internal structures so seeking/reading places an item.
641 itemid: the thing to play.
642 user_entry: true if itemid is a user selection (rather than internally-
643 generated selection such as via PBC) in which case we may have to adjust
644 for differences in numbering.
645 *****************************************************************************/
647 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
649 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
650 input_area_t * p_area;
654 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
655 itemid.num, itemid.type);
657 #define area p_input->stream.pp_areas
659 switch (itemid.type) {
660 case VCDINFO_ITEM_TYPE_TRACK:
662 /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
665 if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
666 LOG_ERR ("Invalid track number %d", itemid.num );
669 p_area = area[itemid.num];
670 p_area->i_part = p_area->i_plugin_data;
671 p_input->stream.b_seekable = 1;
673 case VCDINFO_ITEM_TYPE_SEGMENT:
674 /* Valid segments go from 0...num_segments-1. */
675 if (itemid.num >= p_vcd->num_segments) {
676 LOG_ERR ( "Invalid segment number: %d", itemid.num );
679 vcdinfo_video_segment_type_t segtype =
680 vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
682 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
683 vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
684 (int) segtype, itemid.num);
687 p_area->i_part = itemid.num;
691 case VCDINFO_FILES_VIDEO_NTSC_STILL:
692 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
693 case VCDINFO_FILES_VIDEO_PAL_STILL:
694 case VCDINFO_FILES_VIDEO_PAL_STILL2:
695 p_input->stream.b_seekable = 0;
696 p_vcd->in_still = -5;
699 p_input->stream.b_seekable = 1;
705 case VCDINFO_ITEM_TYPE_LID:
706 /* LIDs go from 1..num_lids. */
707 if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
708 LOG_ERR ( "Invalid LID number: %d", itemid.num );
711 p_vcd->cur_lid = itemid.num;
712 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
714 switch (p_vcd->pxd.descriptor_type) {
716 case PSD_TYPE_SELECTION_LIST:
717 case PSD_TYPE_EXT_SELECTION_LIST: {
718 vcdinfo_itemid_t trans_itemid;
719 uint16_t trans_itemid_num;
721 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
722 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
723 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
724 p_vcd->loop_count = 1;
725 p_vcd->loop_item = trans_itemid;
726 return VCDPlay( p_input, trans_itemid );
730 case PSD_TYPE_PLAY_LIST: {
731 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
733 return vcdplayer_inc_play_item(p_input)
734 ? VLC_SUCCESS : VLC_EGENERIC;
738 case PSD_TYPE_END_LIST:
739 case PSD_TYPE_COMMAND_LIST:
746 case VCDINFO_ITEM_TYPE_ENTRY:
747 /* Entries go from 0..num_entries-1. */
748 if (itemid.num >= p_vcd->num_entries) {
749 LOG_ERR ("Invalid entry number: %d", itemid.num );
752 track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
753 p_area = area[cur_track];
754 p_area->i_part = itemid.num;
755 p_input->stream.b_seekable = 1;
759 LOG_ERR ("unknown entry type" );
763 VCDSetArea( p_input, p_area );
767 p_vcd->play_item = itemid;
769 dbg_print( (INPUT_DBG_CALL),
770 "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d",
771 p_area->i_start, p_area->i_size,
772 p_area->i_tell, p_vcd->cur_lsn );
777 /*****************************************************************************
778 VCDEntryPoints: Reads the information about the entry points on the disc
779 and initializes area information with that.
780 Before calling this track information should have been read in.
781 *****************************************************************************/
783 VCDEntryPoints( input_thread_t * p_input )
785 thread_vcd_data_t * p_vcd;
787 unsigned int i, i_entry_index = 0;
788 unsigned int i_previous_track = CDIO_INVALID_TRACK;
790 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
792 i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
796 p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
798 if( p_vcd->p_entries == NULL )
800 LOG_ERR ("not enough memory for entry points treatment" );
804 p_vcd->num_entries = 0;
806 for( i = 0 ; i < i_nb ; i++ )
808 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
809 if( i_track <= p_input->stream.i_area_nb )
811 p_vcd->p_entries[i] =
812 vcdinfo_get_entry_lsn(p_vcd->vcd, i);
813 p_input->stream.pp_areas[i_track]->i_part_nb ++;
815 /* if this entry belongs to a new track */
816 if( i_track != i_previous_track )
818 /* i_plugin_data is used to store the first entry of the area*/
819 p_input->stream.pp_areas[i_track]->i_plugin_data =
821 i_previous_track = i_track;
822 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
825 p_vcd->num_entries ++;
828 msg_Warn( p_input, "wrong track number found in entry points" );
830 p_vcd->b_valid_ep = true;
834 /*****************************************************************************
835 * VCDSegments: Reads the information about the segments the disc.
836 *****************************************************************************/
838 VCDSegments( input_thread_t * p_input )
840 thread_vcd_data_t * p_vcd;
842 unsigned int num_segments;
845 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
846 num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
848 #define area p_input->stream.pp_areas
850 /* area 0 is reserved for segments. Set Absolute start offset
852 area[0]->i_plugin_data = 0;
853 input_DelArea( p_input, area[0] );
854 input_AddArea( p_input, 0, 0 );
856 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
857 * (off_t)M2F2_SECTOR_SIZE;
858 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
859 * (off_t)M2F2_SECTOR_SIZE;
861 /* Default Segment */
864 /* i_plugin_data is used to store which entry point is the first
865 of the track (area) */
866 area[0]->i_plugin_data = 0;
868 area[0]->i_part_nb = 0;
870 dbg_print( INPUT_DBG_MRL,
871 "area[0] id: %d, i_start: %lld, i_size: %lld",
872 area[0]->i_id, area[0]->i_start, area[0]->i_size );
874 if (num_segments == 0) return 0;
876 /* We have one additional segment allocated so we can get the size
877 by subtracting seg[i+1] - seg[i].
879 p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
880 if( p_vcd->p_segments == NULL )
882 LOG_ERR ("not enough memory for segment treatment" );
886 /* Update the navigation variables without triggering a callback */
887 VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" );
888 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
890 for( i = 0 ; i < num_segments ; i++ )
892 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
893 area[0]->i_part_nb ++;
894 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
895 "chapter", "Adding segment choice");
900 p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
901 vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
906 /*****************************************************************************
907 VCDTracks: initializes area information.
908 Before calling this track information should have been read in.
909 *****************************************************************************/
911 VCDTracks( input_thread_t * p_input )
913 thread_vcd_data_t * p_vcd;
916 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
918 #define area p_input->stream.pp_areas
920 /* We start area addressing for tracks at 1 since the default area 0
921 is reserved for segments */
923 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
925 /* Tracks are Program Chains */
926 input_AddArea( p_input, i, i );
928 /* Absolute start byte offset and byte size */
929 area[i]->i_start = (off_t) p_vcd->p_sectors[i]
930 * (off_t)M2F2_SECTOR_SIZE;
931 area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
932 * (off_t)M2F2_SECTOR_SIZE;
934 /* Current entry being played in track */
937 /* i_plugin_data is used to store which entry point is the first
938 * of the track (area) */
939 area[i]->i_plugin_data = 0;
941 dbg_print( INPUT_DBG_MRL,
942 "area[%d] id: %d, i_start: %lld, i_size: %lld",
943 i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
951 /*****************************************************************************
952 VCDLIDs: Reads the LIST IDs from the LOT.
953 *****************************************************************************/
955 VCDLIDs( input_thread_t * p_input )
957 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
959 p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
960 p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
962 if (vcdinfo_read_psd (p_vcd->vcd)) {
964 vcdinfo_visit_lot (p_vcd->vcd, false);
968 We need to change libvcdinfo to be more robust when there are
969 problems reading the extended PSD. Given that area-highlighting and
970 selection features in the extended PSD haven't been implemented,
971 it's best then to not try to read this at all.
973 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
974 vcdinfo_visit_lot (p_vcd->vcd, true);
978 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
979 "num LIDs=%d", p_vcd->num_lids);
984 /*****************************************************************************
985 * VCDParse: parse command line
986 *****************************************************************************/
988 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid )
990 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
995 p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
999 /* On Win32 we want the VCD access plugin to be explicitly requested,
1000 * we end up with lots of problems otherwise */
1001 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
1004 if( !p_input->psz_name )
1009 psz_parser = psz_source = strdup( p_input->psz_name );
1011 /* Parse input string :
1012 * [device][@[type][title]] */
1013 while( *psz_parser && *psz_parser != '@' )
1018 if( *psz_parser == '@' )
1020 /* Found the divide between the source name and the
1021 type+entry number. */
1028 switch(*psz_parser) {
1030 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
1034 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
1038 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
1042 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
1049 num = strtol( psz_parser, &psz_next, 10 );
1050 if ( *psz_parser != '\0' && *psz_next == '\0')
1052 p_itemid->num = num;
1057 if( !*psz_source ) {
1059 /* No source specified, so figure it out. */
1060 if( !p_input->psz_access ) return NULL;
1062 psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
1065 /* Scan for a CD with a VCD in it. */
1066 char **cd_drives = cdio_get_devices_with_cap(NULL,
1067 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
1068 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
1070 if (NULL == cd_drives) return NULL;
1071 if (cd_drives[0] == NULL) {
1072 cdio_free_device_list(cd_drives);
1075 psz_source = strdup(cd_drives[0]);
1076 cdio_free_device_list(cd_drives);
1080 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
1081 "source=%s entry=%d type=%d",
1082 psz_source, p_itemid->num, p_itemid->type);
1088 Set's start origin subsequent seeks/reads
1091 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
1092 lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
1094 thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1096 p_vcd->origin_lsn = origin_lsn;
1097 p_vcd->cur_lsn = cur_lsn;
1098 p_vcd->end_lsn = end_lsn;
1099 p_vcd->cur_track = cur_track;
1100 p_vcd->play_item.num = cur_entry;
1101 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1103 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
1104 "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
1105 origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
1107 p_input->stream.p_selected_area->i_tell =
1108 (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
1110 VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
1111 "chapter", "Setting entry");
1114 /*****************************************************************************
1115 * vcd_Open: Opens a VCD device or file and returns an opaque handle
1116 *****************************************************************************/
1117 static vcdinfo_obj_t *
1118 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
1120 vcdinfo_obj_t *p_vcdobj;
1123 if( !psz_dev ) return NULL;
1125 /* Set where to log errors messages from libcdio. */
1126 p_vcd_input = (input_thread_t *)p_this;
1127 cdio_log_set_handler ( cdio_log_handler );
1128 vcd_log_set_handler ( vcd_log_handler );
1130 actual_dev=strdup(psz_dev);
1131 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
1141 /****************************************************************************
1142 * VCDReadSector: Read a sector (2324 bytes)
1143 ****************************************************************************/
1145 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
1146 lsn_t cur_lsn, byte_t * p_buffer )
1149 uint8_t subheader [8];
1150 uint8_t data [M2F2_SECTOR_SIZE];
1152 vcdsector_t vcd_sector;
1154 if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
1155 &vcd_sector, cur_lsn, true)
1158 msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
1162 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
1167 /****************************************************************************
1168 Update the "varname" variable to i_num without triggering a callback.
1169 ****************************************************************************/
1171 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
1172 const char *varname, const char *label)
1176 if (NULL != p_vcd_input) {
1177 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1178 dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
1180 var_Change( p_input, varname, i_action, &val, NULL );