1 /*****************************************************************************
2 * vcd.c : VCD input module for vlc
3 * using libcdio, libvcd and libvcdinfo. vlc-specific things tend
5 *****************************************************************************
6 * Copyright (C) 2000 VideoLAN
7 * $Id: access.c,v 1.2 2003/11/07 10:31:38 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 *****************************************************************************/
31 #if 0 // Disabled until this is working
33 #include <vlc/input.h>
35 #include "../../demux/mpeg/system.h"
38 #include "vcdplayer.h"
40 #include <cdio/cdio.h>
41 #include <cdio/logging.h>
42 #include <cdio/util.h>
43 #include <libvcd/info.h>
44 #include <libvcd/logging.h>
48 /* how many blocks VCDRead will read in each loop */
49 #define VCD_BLOCKS_ONCE 20
50 #define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE)
52 /*****************************************************************************
54 *****************************************************************************/
56 /* First those which are accessed from outside (via pointers). */
57 static int VCDOpen ( vlc_object_t * );
58 static void VCDClose ( vlc_object_t * );
59 static int VCDRead ( input_thread_t *, byte_t *, size_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 /****************************************************************************
101 ****************************************************************************/
102 /* FIXME: This variable is a hack. Would be nice to eliminate the
104 static input_thread_t *p_vcd_input = NULL;
107 vcd_debug_callback ( vlc_object_t *p_this, const char *psz_name,
108 vlc_value_t oldval, vlc_value_t val, void *p_data )
110 thread_vcd_data_t *p_vcd;
112 if (NULL == p_vcd_input) return VLC_EGENERIC;
114 p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
116 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
117 msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
118 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
120 p_vcd->i_debug = val.i_int;
124 /* process messages that originate from libcdio. */
126 cdio_log_handler (cdio_log_level_t level, const char message[])
128 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
132 if (p_vcd->i_debug & INPUT_DBG_CDIO)
133 msg_Dbg( p_vcd_input, message);
136 msg_Warn( p_vcd_input, message);
139 case CDIO_LOG_ASSERT:
140 msg_Err( p_vcd_input, message);
143 msg_Warn( p_vcd_input, message,
144 _("The above message had unknown vcdimager log level"),
150 /* process messages that originate from vcdinfo. */
152 vcd_log_handler (vcd_log_level_t level, const char message[])
154 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
158 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
159 msg_Dbg( p_vcd_input, message);
162 msg_Warn( p_vcd_input, message);
166 msg_Err( p_vcd_input, message);
169 msg_Warn( p_vcd_input, "%s\n%s %d", message,
170 _("The above message had unknown vcdimager log level"),
177 * Data reading functions
180 /*****************************************************************************
182 read in meta-information about VCD: the number of tracks, segments,
183 entries, size and starting information. Then set up state variables so
184 that we read/seek starting at the location specified.
186 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
187 and VLC_EGENERIC for some other error.
188 *****************************************************************************/
190 VCDOpen( vlc_object_t *p_this )
192 input_thread_t * p_input = (input_thread_t *)p_this;
193 thread_vcd_data_t * p_vcd;
195 vcdinfo_itemid_t itemid;
198 p_input->pf_read = VCDRead;
199 p_input->pf_seek = VCDSeek;
200 p_input->pf_set_area = VCDSetArea;
201 p_input->pf_set_program = VCDSetProgram;
203 p_vcd = malloc( sizeof(thread_vcd_data_t) );
207 LOG_ERR ("out of memory" );
211 p_input->p_access_data = (void *)p_vcd;
212 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
213 psz_source = VCDParse( p_input, &itemid );
215 if ( NULL == psz_source )
218 return( VLC_EGENERIC );
221 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
223 p_vcd->p_segments = NULL;
224 p_vcd->p_entries = NULL;
227 p_input->i_mtu = VCD_DATA_ONCE;
229 vlc_mutex_lock( &p_input->stream.stream_lock );
231 /* If we are here we can control the pace... */
232 p_input->stream.b_pace_control = 1;
234 p_input->stream.b_seekable = 1;
235 p_input->stream.p_selected_area->i_size = 0;
236 p_input->stream.p_selected_area->i_tell = 0;
238 vlc_mutex_unlock( &p_input->stream.stream_lock );
240 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
242 msg_Warn( p_input, "could not open %s", psz_source );
248 /* Get track information. */
249 p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
250 vcdinfo_get_cd_image(p_vcd->vcd),
253 if( p_vcd->num_tracks < 0 )
254 LOG_ERR ("unable to count tracks" );
255 else if( p_vcd->num_tracks <= 1 )
256 LOG_ERR ("no movie tracks found" );
257 if( p_vcd->num_tracks <= 1)
259 vcdinfo_close( p_vcd->vcd );
264 /* Set stream and area data */
265 vlc_mutex_lock( &p_input->stream.stream_lock );
267 /* Initialize ES structures */
268 input_InitStream( p_input, sizeof( stream_ps_data_t ) );
270 /* disc input method */
271 p_input->stream.i_method = INPUT_METHOD_VCD;
273 p_input->stream.i_area_nb = 1;
276 /* Initialize segment information. */
277 VCDSegments( p_input );
279 /* Initialize track area information. */
280 VCDTracks( p_input );
282 if( VCDEntryPoints( p_input ) < 0 )
284 msg_Warn( p_input, "could not read entry points, will not use them" );
285 p_vcd->b_valid_ep = false;
288 if( VCDLIDs( p_input ) < 0 )
290 msg_Warn( p_input, "could not read entry LIDs" );
293 play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
295 vlc_mutex_unlock( &p_input->stream.stream_lock );
298 vcdinfo_close( p_vcd->vcd );
303 if( !p_input->psz_demux || !*p_input->psz_demux )
306 p_input->psz_demux = "vcdx";
308 p_input->psz_demux = "ps";
315 /*****************************************************************************
316 * VCDClose: closes VCD releasing allocated memory.
317 *****************************************************************************/
319 VCDClose( vlc_object_t *p_this )
321 input_thread_t * p_input = (input_thread_t *)p_this;
322 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
324 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
325 vcdinfo_close( p_vcd->vcd );
327 free( p_vcd->p_entries );
328 free( p_vcd->p_segments );
333 /*****************************************************************************
334 * VCDRead: reads i_len bytes from the VCD into p_buffer.
335 *****************************************************************************
336 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
338 *****************************************************************************/
340 VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
342 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
346 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
350 /* Compute the number of blocks we have to read */
352 i_blocks = i_len / M2F2_SECTOR_SIZE;
354 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
357 if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
358 vcdplayer_read_status_t read_status;
360 /* We've run off of the end of this entry. Do we continue or stop? */
361 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
362 "end reached, cur: %u", p_vcd->cur_lsn );
364 read_status = vcdplayer_pbc_is_on( p_vcd )
365 ? vcdplayer_pbc_nav( p_input )
366 : vcdplayer_non_pbc_nav( p_input );
368 switch (read_status) {
370 /* End reached. Return NULL to indicated this. */
372 /* Some sort of error. */
374 case READ_STILL_FRAME:
376 byte_t * p_buf = p_buffer;
377 p_buf += (i_index*M2F2_SECTOR_SIZE);
378 memset(p_buf, 0, M2F2_SECTOR_SIZE);
381 dbg_print(INPUT_DBG_STILL, "Handled still event\n");
382 return i_read + M2F2_SECTOR_SIZE;
390 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
392 p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
394 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
401 if( p_vcd->b_valid_ep &&
402 /* FIXME kludge so that read does not update chapter
403 * when a manual chapter change was requested and not
404 * yet accomplished */
405 !p_input->stream.p_new_area )
407 unsigned int i_entry = p_input->stream.p_selected_area->i_part;
409 vlc_mutex_lock( &p_input->stream.stream_lock );
411 if( i_entry < p_vcd->num_entries &&
412 p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
414 dbg_print( INPUT_DBG_PBC,
415 "new entry, i_entry %d, sector %d, es %d",
416 i_entry, p_vcd->cur_lsn,
417 p_vcd->p_entries[i_entry] );
418 p_vcd->play_item.num =
419 ++ p_input->stream.p_selected_area->i_part;
420 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
421 VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
422 "chapter", "Setting entry" );
424 vlc_mutex_unlock( &p_input->stream.stream_lock );
427 i_read += M2F2_SECTOR_SIZE;
430 if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
432 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
433 p_vcd->cur_lsn, p_last_sector ) < 0 )
435 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
439 p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
440 p_last_sector, i_len % M2F2_SECTOR_SIZE );
441 i_read += i_len % M2F2_SECTOR_SIZE;
448 /*****************************************************************************
449 * VCDSetProgram: Does nothing since a VCD is mono_program
450 *****************************************************************************/
452 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
454 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
455 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
460 /*****************************************************************************
461 * VCDSetArea: initialize internal data structures and input stream data
462 so set subsequent reading and seeking to reflect that we are
463 at track x, entry or segment y.
464 This is called for each user navigation request, e.g. the GUI
465 Chapter/Title selections or in initial MRL parsing.
466 ****************************************************************************/
468 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
470 thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
471 unsigned int i_entry = p_area->i_part;
472 track_t i_track = p_area->i_id;
473 int old_seekable = p_input->stream.b_seekable;
474 unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb;
476 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
477 "track: %d, entry %d, seekable %d",
478 i_track, i_entry, old_seekable );
480 /* we can't use the interface slider until initilization is complete */
481 p_input->stream.b_seekable = 0;
483 if( p_area != p_input->stream.p_selected_area )
487 /* If is the result of a track change, make the entry valid. */
488 if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
489 i_entry = p_area->i_plugin_data;
491 /* Change the default area */
492 p_input->stream.p_selected_area = p_area;
494 /* Update the navigation variables without triggering a callback */
495 VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
498 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
499 for( i = p_area->i_plugin_data; i < i_nb; i++ )
501 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
502 "chapter", "Adding entry choice");
507 VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
508 p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
511 VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
512 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
513 p_vcd->p_sectors[i_track+1],
516 p_input->stream.b_seekable = old_seekable;
517 /* warn interface that something has changed */
518 p_input->stream.b_changed = 1;
524 /****************************************************************************
526 ****************************************************************************/
528 VCDSeek( input_thread_t * p_input, off_t i_off )
530 thread_vcd_data_t * p_vcd;
531 unsigned int i_entry=0; /* invalid entry */
533 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
535 p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
537 vlc_mutex_lock( &p_input->stream.stream_lock );
538 #define p_area p_input->stream.p_selected_area
540 if( p_vcd->b_valid_ep )
542 for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ )
544 if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
546 VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
547 "chapter", "Setting entry" );
551 p_vcd->play_item.num = p_area->i_part = i_entry;
552 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
556 p_input->stream.p_selected_area->i_tell = i_off;
558 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
559 "orig %d, cur: %d, offset: %lld, start: %lld, entry %d",
560 p_vcd->origin_lsn, p_vcd->cur_lsn, i_off,
561 p_input->stream.p_selected_area->i_start, i_entry );
563 vlc_mutex_unlock( &p_input->stream.stream_lock );
566 /*****************************************************************************
567 VCDPlay: set up internal structures so seeking/reading places an item.
568 itemid: the thing to play.
569 user_entry: true if itemid is a user selection (rather than internally-
570 generated selection such as via PBC) in which case we may have to adjust
571 for differences in numbering.
572 *****************************************************************************/
574 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
576 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
577 input_area_t * p_area;
581 #define area p_input->stream.pp_areas
583 switch (itemid.type) {
584 case VCDINFO_ITEM_TYPE_TRACK:
586 /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
589 if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
590 LOG_ERR ("Invalid track number %d", itemid.num );
593 p_area = area[itemid.num];
594 p_area->i_part = p_area->i_plugin_data;
595 p_input->stream.b_seekable = 1;
597 case VCDINFO_ITEM_TYPE_SEGMENT:
598 /* Valid segments go from 0...num_segments-1. */
599 if (itemid.num >= p_vcd->num_segments) {
600 LOG_ERR ( "Invalid segment number: %d", itemid.num );
603 vcdinfo_video_segment_type_t segtype =
604 vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
606 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
607 vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
608 (int) segtype, itemid.num);
611 p_area->i_part = itemid.num;
615 case VCDINFO_FILES_VIDEO_NTSC_STILL:
616 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
617 case VCDINFO_FILES_VIDEO_PAL_STILL:
618 case VCDINFO_FILES_VIDEO_PAL_STILL2:
619 p_input->stream.b_seekable = 0;
620 p_vcd->in_still = -5;
623 p_input->stream.b_seekable = 1;
629 case VCDINFO_ITEM_TYPE_LID:
630 /* LIDs go from 1..num_lids. */
631 if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
632 LOG_ERR ( "Invalid LID number: %d", itemid.num );
635 p_vcd->cur_lid = itemid.num;
636 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
638 switch (p_vcd->pxd.descriptor_type) {
640 case PSD_TYPE_SELECTION_LIST:
641 case PSD_TYPE_EXT_SELECTION_LIST: {
642 vcdinfo_itemid_t trans_itemid;
643 uint16_t trans_itemid_num;
645 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
646 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
647 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
648 p_vcd->loop_count = 1;
649 p_vcd->loop_item = trans_itemid;
650 return VCDPlay( p_input, trans_itemid );
654 case PSD_TYPE_PLAY_LIST: {
655 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
657 return vcdplayer_inc_play_item(p_input)
658 ? VLC_SUCCESS : VLC_EGENERIC;
662 case PSD_TYPE_END_LIST:
663 case PSD_TYPE_COMMAND_LIST:
670 case VCDINFO_ITEM_TYPE_ENTRY:
671 /* Entries go from 0..num_entries-1. */
672 if (itemid.num >= p_vcd->num_entries) {
673 LOG_ERR ("Invalid entry number: %d", itemid.num );
676 track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
677 p_area = area[cur_track];
678 p_area->i_part = itemid.num;
679 p_input->stream.b_seekable = 1;
683 LOG_ERR ("unknown entry type" );
687 VCDSetArea( p_input, p_area );
691 p_vcd->play_item = itemid;
693 dbg_print( (INPUT_DBG_CALL),
694 "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d",
695 p_area->i_start, p_area->i_size,
696 p_area->i_tell, p_vcd->cur_lsn );
701 /*****************************************************************************
702 VCDEntryPoints: Reads the information about the entry points on the disc
703 and initializes area information with that.
704 Before calling this track information should have been read in.
705 *****************************************************************************/
707 VCDEntryPoints( input_thread_t * p_input )
709 thread_vcd_data_t * p_vcd;
711 unsigned int i, i_entry_index = 0;
712 unsigned int i_previous_track = CDIO_INVALID_TRACK;
714 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
716 i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
720 p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
722 if( p_vcd->p_entries == NULL )
724 LOG_ERR ("not enough memory for entry points treatment" );
728 p_vcd->num_entries = 0;
730 for( i = 0 ; i < i_nb ; i++ )
732 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
733 if( i_track <= p_input->stream.i_area_nb )
735 p_vcd->p_entries[i] =
736 vcdinfo_get_entry_lsn(p_vcd->vcd, i);
737 p_input->stream.pp_areas[i_track]->i_part_nb ++;
739 /* if this entry belongs to a new track */
740 if( i_track != i_previous_track )
742 /* i_plugin_data is used to store the first entry of the area*/
743 p_input->stream.pp_areas[i_track]->i_plugin_data =
745 i_previous_track = i_track;
746 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
749 p_vcd->num_entries ++;
752 msg_Warn( p_input, "wrong track number found in entry points" );
754 p_vcd->b_valid_ep = true;
758 /*****************************************************************************
759 * VCDSegments: Reads the information about the segments the disc.
760 *****************************************************************************/
762 VCDSegments( input_thread_t * p_input )
764 thread_vcd_data_t * p_vcd;
766 unsigned int num_segments;
769 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
770 num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
772 #define area p_input->stream.pp_areas
774 /* area 0 is reserved for segments. Set Absolute start offset
776 area[0]->i_plugin_data = 0;
777 input_DelArea( p_input, area[0] );
778 input_AddArea( p_input, 0, 0 );
780 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
781 * (off_t)M2F2_SECTOR_SIZE;
782 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
783 * (off_t)M2F2_SECTOR_SIZE;
785 /* Default Segment */
788 /* i_plugin_data is used to store which entry point is the first
789 of the track (area) */
790 area[0]->i_plugin_data = 0;
792 area[0]->i_part_nb = 0;
794 dbg_print( INPUT_DBG_MRL, "area id %d, for segment track %d",
797 if (num_segments == 0) return 0;
799 /* We have one additional segment allocated so we can get the size
800 by subtracting seg[i+1] - seg[i].
802 p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
803 if( p_vcd->p_segments == NULL )
805 LOG_ERR ("not enough memory for segment treatment" );
809 /* Update the navigation variables without triggering a callback */
810 VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" );
811 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
813 for( i = 0 ; i < num_segments ; i++ )
815 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
816 area[0]->i_part_nb ++;
817 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
818 "chapter", "Adding segment choice");
823 p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
824 vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
829 /*****************************************************************************
830 VCDTracks: initializes area information.
831 Before calling this track information should have been read in.
832 *****************************************************************************/
834 VCDTracks( input_thread_t * p_input )
836 thread_vcd_data_t * p_vcd;
839 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
841 #define area p_input->stream.pp_areas
843 /* We start area addressing for tracks at 1 since the default area 0
844 is reserved for segments */
846 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
848 /* Tracks are Program Chains */
849 input_AddArea( p_input, i, i );
851 /* Absolute start byte offset and byte size */
852 area[i]->i_start = (off_t) p_vcd->p_sectors[i]
853 * (off_t)M2F2_SECTOR_SIZE;
854 area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
855 * (off_t)M2F2_SECTOR_SIZE;
857 /* Current entry being played in track */
860 /* i_plugin_data is used to store which entry point is the first
861 * of the track (area) */
862 area[i]->i_plugin_data = 0;
864 dbg_print( INPUT_DBG_MRL,
865 "area[%d] id: %d, i_start: %lld, i_size: %lld",
866 i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
874 /*****************************************************************************
875 VCDLIDs: Reads the LIST IDs from the LOT.
876 *****************************************************************************/
878 VCDLIDs( input_thread_t * p_input )
880 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
882 p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
883 p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
885 if (vcdinfo_read_psd (p_vcd->vcd)) {
887 vcdinfo_visit_lot (p_vcd->vcd, false);
891 We need to change libvcdinfo to be more robust when there are
892 problems reading the extended PSD. Given that area-highlighting and
893 selection features in the extended PSD haven't been implemented,
894 it's best then to not try to read this at all.
896 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
897 vcdinfo_visit_lot (p_vcd->vcd, true);
901 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
902 "num LIDs=%d", p_vcd->num_lids);
907 /*****************************************************************************
908 * VCDParse: parse command line
909 *****************************************************************************/
911 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid )
913 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
918 p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
922 /* On Win32 we want the VCD access plugin to be explicitly requested,
923 * we end up with lots of problems otherwise */
924 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
927 if( !p_input->psz_name )
932 psz_parser = psz_source = strdup( p_input->psz_name );
934 /* Parse input string :
935 * [device][@[type][title]] */
936 while( *psz_parser && *psz_parser != '@' )
941 if( *psz_parser == '@' )
943 /* Found the divide between the source name and the
944 type+entry number. */
951 switch(*psz_parser) {
953 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
957 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
961 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
965 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
972 num = strtol( psz_parser, &psz_next, 10 );
973 if ( *psz_parser != '\0' && *psz_next == '\0')
982 if( !p_input->psz_access )
986 psz_source = config_GetPsz( p_input, "vcd" );
987 if( !psz_source ) return NULL;
990 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
991 "source=%s entry=%d type=%d",
992 psz_source, p_itemid->num, p_itemid->type);
998 Set's start origin subsequent seeks/reads
1001 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
1002 lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
1004 thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1006 p_vcd->origin_lsn = origin_lsn;
1007 p_vcd->cur_lsn = cur_lsn;
1008 p_vcd->end_lsn = end_lsn;
1009 p_vcd->cur_track = cur_track;
1010 p_vcd->play_item.num = cur_entry;
1011 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1013 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
1014 "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
1015 origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
1017 p_input->stream.p_selected_area->i_tell =
1018 (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
1020 VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
1021 "chapter", "Setting entry");
1024 /*****************************************************************************
1025 * vcd_Open: Opens a VCD device or file and returns an opaque handle
1026 *****************************************************************************/
1027 static vcdinfo_obj_t *
1028 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
1030 vcdinfo_obj_t *p_vcdobj;
1033 if( !psz_dev ) return NULL;
1035 /* Set where to log errors messages from libcdio. */
1036 p_vcd_input = (input_thread_t *)p_this;
1037 cdio_log_set_handler ( cdio_log_handler );
1038 vcd_log_set_handler ( vcd_log_handler );
1040 actual_dev=strdup(psz_dev);
1041 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
1051 /****************************************************************************
1052 * VCDReadSector: Read a sector (2324 bytes)
1053 ****************************************************************************/
1055 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
1056 lsn_t cur_lsn, byte_t * p_buffer )
1059 uint8_t subheader [8];
1060 uint8_t data [M2F2_SECTOR_SIZE];
1062 vcdsector_t vcd_sector;
1064 if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
1065 &vcd_sector, cur_lsn, true)
1068 msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
1072 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
1077 /****************************************************************************
1078 Update the "varname" variable to i_num without triggering a callback.
1079 ****************************************************************************/
1081 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
1082 const char *varname, const char *label)
1086 if (NULL != p_vcd_input) {
1087 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1088 dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
1090 var_Change( p_input, varname, i_action, &val, NULL );