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: vcd.c,v 1.1 2003/10/04 18:55:13 gbazin 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>
34 #include "../../demux/mpeg/system.h"
37 #include "vcdplayer.h"
39 #include <cdio/cdio.h>
40 #include <cdio/cd_types.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 /*****************************************************************************
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 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";
351 /*****************************************************************************
352 * VCDClose: closes VCD releasing allocated memory.
353 *****************************************************************************/
355 VCDClose( vlc_object_t *p_this )
357 input_thread_t * p_input = (input_thread_t *)p_this;
358 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
360 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
361 vcdinfo_close( p_vcd->vcd );
363 free( p_vcd->p_entries );
364 free( p_vcd->p_segments );
369 /*****************************************************************************
370 * VCDRead: reads i_len bytes from the VCD into p_buffer.
371 *****************************************************************************
372 * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
374 *****************************************************************************/
376 VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
378 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
382 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
386 /* Compute the number of blocks we have to read */
388 i_blocks = i_len / M2F2_SECTOR_SIZE;
390 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
393 if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
394 vcdplayer_read_status_t read_status;
396 /* We've run off of the end of this entry. Do we continue or stop? */
397 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
398 "end reached, cur: %u", p_vcd->cur_lsn );
400 read_status = vcdplayer_pbc_is_on( p_vcd )
401 ? vcdplayer_pbc_nav( p_input )
402 : vcdplayer_non_pbc_nav( p_input );
404 switch (read_status) {
406 /* End reached. Return NULL to indicated this. */
408 /* Some sort of error. */
410 case READ_STILL_FRAME:
412 byte_t * p_buf = p_buffer;
413 p_buf += (i_index*M2F2_SECTOR_SIZE);
414 memset(p_buf, 0, M2F2_SECTOR_SIZE);
417 dbg_print(INPUT_DBG_STILL, "Handled still event\n");
418 return i_read + M2F2_SECTOR_SIZE;
426 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
428 p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
430 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
437 if( p_vcd->b_valid_ep &&
438 /* FIXME kludge so that read does not update chapter
439 * when a manual chapter change was requested and not
440 * yet accomplished */
441 !p_input->stream.p_new_area )
443 unsigned int i_entry = p_input->stream.p_selected_area->i_part;
445 vlc_mutex_lock( &p_input->stream.stream_lock );
447 if( i_entry < p_vcd->num_entries &&
448 p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
450 dbg_print( INPUT_DBG_PBC,
451 "new entry, i_entry %d, sector %d, es %d",
452 i_entry, p_vcd->cur_lsn,
453 p_vcd->p_entries[i_entry] );
454 p_vcd->play_item.num =
455 ++ p_input->stream.p_selected_area->i_part;
456 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
457 VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
458 "chapter", "Setting entry" );
460 vlc_mutex_unlock( &p_input->stream.stream_lock );
463 i_read += M2F2_SECTOR_SIZE;
466 if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
468 if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
469 p_vcd->cur_lsn, p_last_sector ) < 0 )
471 LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
475 p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
476 p_last_sector, i_len % M2F2_SECTOR_SIZE );
477 i_read += i_len % M2F2_SECTOR_SIZE;
484 /*****************************************************************************
485 * VCDSetProgram: Does nothing since a VCD is mono_program
486 *****************************************************************************/
488 VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
490 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
491 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
496 /*****************************************************************************
497 * VCDSetArea: initialize internal data structures and input stream data
498 so set subsequent reading and seeking to reflect that we are
499 at track x, entry or segment y.
500 This is called for each user navigation request, e.g. the GUI
501 Chapter/Title selections or in initial MRL parsing.
502 ****************************************************************************/
504 VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
506 thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
507 unsigned int i_entry = p_area->i_part;
508 track_t i_track = p_area->i_id;
509 int old_seekable = p_input->stream.b_seekable;
510 unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb;
512 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
513 "track: %d, entry %d, seekable %d",
514 i_track, i_entry, old_seekable );
516 /* we can't use the interface slider until initilization is complete */
517 p_input->stream.b_seekable = 0;
519 if( p_area != p_input->stream.p_selected_area )
523 /* If is the result of a track change, make the entry valid. */
524 if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
525 i_entry = p_area->i_plugin_data;
527 /* Change the default area */
528 p_input->stream.p_selected_area = p_area;
530 /* Update the navigation variables without triggering a callback */
531 VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
534 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
535 for( i = p_area->i_plugin_data; i < i_nb; i++ )
537 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
538 "chapter", "Adding entry choice");
543 VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
544 p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
547 VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
548 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
549 p_vcd->p_sectors[i_track+1],
552 p_input->stream.b_seekable = old_seekable;
553 /* warn interface that something has changed */
554 p_input->stream.b_changed = 1;
560 /****************************************************************************
562 ****************************************************************************/
564 VCDSeek( input_thread_t * p_input, off_t i_off )
566 thread_vcd_data_t * p_vcd;
567 unsigned int i_entry=0; /* invalid entry */
569 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
571 p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
573 vlc_mutex_lock( &p_input->stream.stream_lock );
574 #define p_area p_input->stream.p_selected_area
576 if( p_vcd->b_valid_ep )
578 for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ )
580 if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
582 VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
583 "chapter", "Setting entry" );
587 p_vcd->play_item.num = p_area->i_part = i_entry;
588 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
592 p_input->stream.p_selected_area->i_tell = i_off;
594 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
595 "orig %d, cur: %d, offset: %lld, start: %lld, entry %d",
596 p_vcd->origin_lsn, p_vcd->cur_lsn, i_off,
597 p_input->stream.p_selected_area->i_start, i_entry );
599 vlc_mutex_unlock( &p_input->stream.stream_lock );
602 /*****************************************************************************
603 VCDPlay: set up internal structures so seeking/reading places an item.
604 itemid: the thing to play.
605 user_entry: true if itemid is a user selection (rather than internally-
606 generated selection such as via PBC) in which case we may have to adjust
607 for differences in numbering.
608 *****************************************************************************/
610 VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
612 thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
613 input_area_t * p_area;
617 #define area p_input->stream.pp_areas
619 switch (itemid.type) {
620 case VCDINFO_ITEM_TYPE_TRACK:
622 /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
625 if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
626 LOG_ERR ("Invalid track number %d", itemid.num );
629 p_area = area[itemid.num];
630 p_area->i_part = p_area->i_plugin_data;
631 p_input->stream.b_seekable = 1;
633 case VCDINFO_ITEM_TYPE_SEGMENT:
634 /* Valid segments go from 0...num_segments-1. */
635 if (itemid.num >= p_vcd->num_segments) {
636 LOG_ERR ( "Invalid segment number: %d", itemid.num );
639 vcdinfo_video_segment_type_t segtype =
640 vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
642 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
643 vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
644 (int) segtype, itemid.num);
647 p_area->i_part = itemid.num;
651 case VCDINFO_FILES_VIDEO_NTSC_STILL:
652 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
653 case VCDINFO_FILES_VIDEO_PAL_STILL:
654 case VCDINFO_FILES_VIDEO_PAL_STILL2:
655 p_input->stream.b_seekable = 0;
656 p_vcd->in_still = -5;
659 p_input->stream.b_seekable = 1;
665 case VCDINFO_ITEM_TYPE_LID:
666 /* LIDs go from 1..num_lids. */
667 if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
668 LOG_ERR ( "Invalid LID number: %d", itemid.num );
671 p_vcd->cur_lid = itemid.num;
672 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
674 switch (p_vcd->pxd.descriptor_type) {
676 case PSD_TYPE_SELECTION_LIST:
677 case PSD_TYPE_EXT_SELECTION_LIST: {
678 vcdinfo_itemid_t trans_itemid;
679 uint16_t trans_itemid_num;
681 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
682 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
683 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
684 p_vcd->loop_count = 1;
685 p_vcd->loop_item = trans_itemid;
686 return VCDPlay( p_input, trans_itemid );
690 case PSD_TYPE_PLAY_LIST: {
691 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
693 return vcdplayer_inc_play_item(p_input)
694 ? VLC_SUCCESS : VLC_EGENERIC;
698 case PSD_TYPE_END_LIST:
699 case PSD_TYPE_COMMAND_LIST:
706 case VCDINFO_ITEM_TYPE_ENTRY:
707 /* Entries go from 0..num_entries-1. */
708 if (itemid.num >= p_vcd->num_entries) {
709 LOG_ERR ("Invalid entry number: %d", itemid.num );
712 track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
713 p_area = area[cur_track];
714 p_area->i_part = itemid.num;
715 p_input->stream.b_seekable = 1;
719 LOG_ERR ("unknown entry type" );
723 VCDSetArea( p_input, p_area );
727 p_vcd->play_item = itemid;
729 dbg_print( (INPUT_DBG_CALL),
730 "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d",
731 p_area->i_start, p_area->i_size,
732 p_area->i_tell, p_vcd->cur_lsn );
737 /*****************************************************************************
738 VCDEntryPoints: Reads the information about the entry points on the disc
739 and initializes area information with that.
740 Before calling this track information should have been read in.
741 *****************************************************************************/
743 VCDEntryPoints( input_thread_t * p_input )
745 thread_vcd_data_t * p_vcd;
747 unsigned int i, i_entry_index = 0;
748 unsigned int i_previous_track = CDIO_INVALID_TRACK;
750 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
752 i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
756 p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
758 if( p_vcd->p_entries == NULL )
760 LOG_ERR ("not enough memory for entry points treatment" );
764 p_vcd->num_entries = 0;
766 for( i = 0 ; i < i_nb ; i++ )
768 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
769 if( i_track <= p_input->stream.i_area_nb )
771 p_vcd->p_entries[i] =
772 vcdinfo_get_entry_lsn(p_vcd->vcd, i);
773 p_input->stream.pp_areas[i_track]->i_part_nb ++;
775 /* if this entry belongs to a new track */
776 if( i_track != i_previous_track )
778 /* i_plugin_data is used to store the first entry of the area*/
779 p_input->stream.pp_areas[i_track]->i_plugin_data =
781 i_previous_track = i_track;
782 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
785 p_vcd->num_entries ++;
788 msg_Warn( p_input, "wrong track number found in entry points" );
790 p_vcd->b_valid_ep = true;
794 /*****************************************************************************
795 * VCDSegments: Reads the information about the segments the disc.
796 *****************************************************************************/
798 VCDSegments( input_thread_t * p_input )
800 thread_vcd_data_t * p_vcd;
802 unsigned int num_segments;
805 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
806 num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
808 #define area p_input->stream.pp_areas
810 /* area 0 is reserved for segments. Set Absolute start offset
812 area[0]->i_plugin_data = 0;
813 input_DelArea( p_input, area[0] );
814 input_AddArea( p_input, 0, 0 );
816 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
817 * (off_t)M2F2_SECTOR_SIZE;
818 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
819 * (off_t)M2F2_SECTOR_SIZE;
821 /* Default Segment */
824 /* i_plugin_data is used to store which entry point is the first
825 of the track (area) */
826 area[0]->i_plugin_data = 0;
828 area[0]->i_part_nb = 0;
830 dbg_print( INPUT_DBG_MRL, "area id %d, for segment track %d",
833 if (num_segments == 0) return 0;
835 /* We have one additional segment allocated so we can get the size
836 by subtracting seg[i+1] - seg[i].
838 p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
839 if( p_vcd->p_segments == NULL )
841 LOG_ERR ("not enough memory for segment treatment" );
845 /* Update the navigation variables without triggering a callback */
846 VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" );
847 var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
849 for( i = 0 ; i < num_segments ; i++ )
851 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
852 area[0]->i_part_nb ++;
853 VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
854 "chapter", "Adding segment choice");
859 p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
860 vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
865 /*****************************************************************************
866 VCDTracks: initializes area information.
867 Before calling this track information should have been read in.
868 *****************************************************************************/
870 VCDTracks( input_thread_t * p_input )
872 thread_vcd_data_t * p_vcd;
875 p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
877 #define area p_input->stream.pp_areas
879 /* We start area addressing for tracks at 1 since the default area 0
880 is reserved for segments */
882 for( i = 1 ; i < p_vcd->num_tracks ; i++ )
884 /* Tracks are Program Chains */
885 input_AddArea( p_input, i, i );
887 /* Absolute start byte offset and byte size */
888 area[i]->i_start = (off_t) p_vcd->p_sectors[i]
889 * (off_t)M2F2_SECTOR_SIZE;
890 area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
891 * (off_t)M2F2_SECTOR_SIZE;
893 /* Current entry being played in track */
896 /* i_plugin_data is used to store which entry point is the first
897 * of the track (area) */
898 area[i]->i_plugin_data = 0;
900 dbg_print( INPUT_DBG_MRL,
901 "area[%d] id: %d, i_start: %lld, i_size: %lld",
902 i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
910 /*****************************************************************************
911 VCDLIDs: Reads the LIST IDs from the LOT.
912 *****************************************************************************/
914 VCDLIDs( input_thread_t * p_input )
916 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
918 p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
919 p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
921 if (vcdinfo_read_psd (p_vcd->vcd)) {
923 vcdinfo_visit_lot (p_vcd->vcd, false);
925 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
926 vcdinfo_visit_lot (p_vcd->vcd, true);
929 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
930 "num LIDs=%d", p_vcd->num_lids);
935 /*****************************************************************************
936 * VCDParse: parse command line
937 *****************************************************************************/
939 VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid )
941 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
946 p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
950 /* On Win32 we want the VCD access plugin to be explicitly requested,
951 * we end up with lots of problems otherwise */
952 if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
955 if( !p_input->psz_name )
960 psz_parser = psz_source = strdup( p_input->psz_name );
962 /* Parse input string :
963 * [device][@[type][title]] */
964 while( *psz_parser && *psz_parser != '@' )
969 if( *psz_parser == '@' )
971 /* Found the divide between the source name and the
972 type+entry number. */
979 switch(*psz_parser) {
981 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
985 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
989 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
993 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
1000 num = strtol( psz_parser, &psz_next, 10 );
1001 if ( *psz_parser != '\0' && *psz_next == '\0')
1003 p_itemid->num = num;
1008 if( !*psz_source ) {
1010 /* No source specified, so figure it out. */
1011 if( !p_input->psz_access ) return NULL;
1013 psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
1016 /* Scan for a CD with a VCD in it. */
1017 char **cd_drives = cdio_get_devices_with_cap(NULL,
1018 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
1019 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
1021 if (NULL == cd_drives) return NULL;
1022 if (cd_drives[0] == NULL) {
1023 cdio_free_device_list(cd_drives);
1026 psz_source = strdup(cd_drives[0]);
1027 cdio_free_device_list(cd_drives);
1031 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
1032 "source=%s entry=%d type=%d",
1033 psz_source, p_itemid->num, p_itemid->type);
1039 Set's start origin subsequent seeks/reads
1042 VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
1043 lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
1045 thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
1047 p_vcd->origin_lsn = origin_lsn;
1048 p_vcd->cur_lsn = cur_lsn;
1049 p_vcd->end_lsn = end_lsn;
1050 p_vcd->cur_track = cur_track;
1051 p_vcd->play_item.num = cur_entry;
1052 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1054 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
1055 "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
1056 origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
1058 p_input->stream.p_selected_area->i_tell =
1059 (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
1061 VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
1062 "chapter", "Setting entry");
1065 /*****************************************************************************
1066 * vcd_Open: Opens a VCD device or file and returns an opaque handle
1067 *****************************************************************************/
1068 static vcdinfo_obj_t *
1069 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
1071 vcdinfo_obj_t *p_vcdobj;
1074 if( !psz_dev ) return NULL;
1076 /* Set where to log errors messages from libcdio. */
1077 p_vcd_input = (input_thread_t *)p_this;
1078 cdio_log_set_handler ( cdio_log_handler );
1079 vcd_log_set_handler ( vcd_log_handler );
1081 actual_dev=strdup(psz_dev);
1082 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
1092 /****************************************************************************
1093 * VCDReadSector: Read a sector (2324 bytes)
1094 ****************************************************************************/
1096 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
1097 lsn_t cur_lsn, byte_t * p_buffer )
1100 uint8_t subheader [8];
1101 uint8_t data [M2F2_SECTOR_SIZE];
1103 vcdsector_t vcd_sector;
1105 if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
1106 &vcd_sector, cur_lsn, true)
1109 msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
1113 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
1118 /****************************************************************************
1119 Update the "varname" variable to i_num without triggering a callback.
1120 ****************************************************************************/
1122 VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
1123 const char *varname, const char *label)
1127 if (NULL != p_vcd_input) {
1128 thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
1129 dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
1131 var_Change( p_input, varname, i_action, &val, NULL );