1 /*****************************************************************************
2 * vcd.c : VCD input module for vlc using libcdio, libvcd and libvcdinfo.
3 * vlc-specific things tend to go here.
4 *****************************************************************************
5 * Copyright (C) 2000, 2003, 2004 VideoLAN
8 * Authors: Rocky Bernstein <rocky@panix.com>
9 * Some code is based on the non-libcdio VCD plugin (as there really
10 * isn't real developer documentation yet on how to write a
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
34 #include <vlc/input.h>
41 #include <cdio/cdio.h>
42 #include <cdio/cd_types.h>
43 #include <cdio/logging.h>
44 #include <cdio/util.h>
45 #include <libvcd/info.h>
46 #include <libvcd/logging.h>
48 /* how many blocks VCDRead will read in each loop */
49 #define VCD_BLOCKS_ONCE 20
51 /*****************************************************************************
53 *****************************************************************************/
55 /* First those which are accessed from outside (via pointers). */
56 static block_t *VCDReadBlock ( access_t * );
58 static int VCDControl ( access_t *p_access, int i_query,
61 /* Now those which are strictly internal */
62 static void VCDSetOrigin ( access_t *p_access,
64 lsn_t i_lsn, lsn_t end_lsn,
66 const vcdinfo_itemid_t * p_itemid );
67 static int VCDEntryPoints ( access_t * );
68 static int VCDLIDs ( access_t * );
70 static int VCDSegments ( access_t * );
72 static int VCDTitles ( access_t * );
73 static int VCDReadSector ( vlc_object_t *p_this,
74 const vcdinfo_obj_t *p_vcd, lsn_t i_lsn,
76 static char *VCDParse ( access_t *,
77 /*out*/ vcdinfo_itemid_t * p_itemid ,
78 /*out*/ vlc_bool_t *play_single_item );
80 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
81 const char *p_varname, char *p_label,
82 const char *p_debug_label );
84 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
86 /****************************************************************************
88 ****************************************************************************/
90 /* FIXME: This variable is a hack. Would be nice to eliminate the
93 static access_t *p_vcd_access = NULL;
95 /* process messages that originate from libcdio. */
97 cdio_log_handler (cdio_log_level_t level, const char message[])
99 const access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
103 if (p_vcd->i_debug & INPUT_DBG_CDIO)
104 msg_Dbg( p_vcd_access, message);
107 msg_Warn( p_vcd_access, message);
110 case CDIO_LOG_ASSERT:
111 msg_Err( p_vcd_access, message);
114 msg_Warn( p_vcd_access, message,
115 _("The above message had unknown log level"),
121 /* process messages that originate from vcdinfo. */
123 vcd_log_handler (vcd_log_level_t level, const char message[])
125 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
129 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
130 msg_Dbg( p_vcd_access, message);
133 msg_Warn( p_vcd_access, message);
137 msg_Err( p_vcd_access, message);
140 msg_Warn( p_vcd_access, "%s\n%s %d", message,
141 _("The above message had unknown vcdimager log level"),
147 /*****************************************************************************
148 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
149 NULL is returned if something went wrong.
150 *****************************************************************************/
152 VCDReadBlock( access_t * p_access )
154 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
156 int i_blocks = VCD_BLOCKS_ONCE;
158 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
162 dbg_print( (INPUT_DBG_CALL), "lsn: %lu",
163 (long unsigned int) p_vcd->i_lsn );
165 /* Compute the number of blocks we have to read */
167 i_blocks = VCD_BLOCKS_ONCE ;
169 /* Allocate a block for the reading */
170 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
172 msg_Err( p_access, "cannot get a new block of size: %i",
173 i_blocks * M2F2_SECTOR_SIZE );
174 block_Release( p_block );
178 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
181 if ( p_vcd->i_lsn == p_vcd->end_lsn ) {
182 vcdplayer_read_status_t read_status;
184 /* We've run off of the end of this entry. Do we continue or stop? */
185 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
186 "end reached, cur: %lu",
187 (long unsigned int) p_vcd->i_lsn );
189 read_status = vcdplayer_pbc_is_on( p_vcd )
190 ? vcdplayer_pbc_nav( p_access )
191 : vcdplayer_non_pbc_nav( p_access );
193 switch (read_status) {
195 /* End reached. Return NULL to indicated this. */
197 /* Some sort of error. */
200 case READ_STILL_FRAME:
202 /* Reached the end of a still frame. */
203 byte_t * p_buf = (byte_t *) p_block->p_buffer;
205 p_buf += (i_read*M2F2_SECTOR_SIZE);
206 memset(p_buf, 0, M2F2_SECTOR_SIZE);
209 dbg_print(INPUT_DBG_STILL, "Handled still event");
211 p_vcd->p_intf->p_sys->b_still = VLC_TRUE;
212 var_SetInteger( p_access, "state", PAUSE_S );
222 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
224 (byte_t *) p_block->p_buffer
225 + (i_read*M2F2_SECTOR_SIZE) ) < 0 )
227 LOG_ERR ("could not read sector %lu",
228 (long unsigned int) p_vcd->i_lsn );
229 /* Try to skip one sector (in case of bad sectors) */
231 p_access->info.i_pos += M2F2_SECTOR_SIZE;
236 p_access->info.i_pos += M2F2_SECTOR_SIZE;
238 /* Update seekpoint */
239 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type )
241 unsigned int i_entry = p_vcd->play_item.num+1;
243 if (p_vcd->i_lsn >= vcdinfo_get_entry_lba(p_vcd->vcd, i_entry))
245 const track_t i_track = p_vcd->i_track;
246 p_vcd->play_item.num = i_entry;
247 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "entry change" );
248 VCDSetOrigin( p_access,
249 vcdinfo_get_track_lba(p_vcd->vcd, i_track),
250 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
251 vcdinfo_get_track_lba(p_vcd->vcd, i_track+1),
252 i_track, &(p_vcd->play_item) );
257 if ( i_read != i_blocks ) /* this should not happen */
259 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
260 p_vcd->i_lsn, p_last_sector ) < 0 )
262 LOG_ERR ("could not read sector %lu",
263 (long unsigned int) p_vcd->i_lsn );
274 /****************************************************************************
276 ****************************************************************************/
278 VCDSeek( access_t * p_access, int64_t i_pos )
280 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
283 access_vcd_data_t *p_vcd =
284 (access_vcd_data_t *)p_vcd_access->p_sys;
285 const input_title_t *t = p_vcd->p_title[p_access->info.i_title];
287 unsigned int i_entry=VCDINFO_INVALID_ENTRY;
289 /* Next sector to read */
290 p_access->info.i_pos = i_pos;
291 p_vcd->i_lsn = (i_pos / (int64_t)M2F2_SECTOR_SIZE) +
295 if( p_vcd->b_valid_ep )
297 for( i_entry = 0 ; i_entry < p_vcd->i_entries ; i_entry ++ )
299 if( p_vcd->i_lsn < p_vcd->p_entries[i_entry] )
301 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
302 "chapter", _("Entry"), "Setting entry" );
306 p_vcd->play_item.num = i_entry;
307 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
310 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
311 "orig %lu, cur: %lu, offset: %lld, entry %d",
312 (long unsigned int) p_vcd->origin_lsn,
313 (long unsigned int) p_vcd->i_lsn, i_pos,
317 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
319 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
320 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
323 /* Update current seekpoint */
324 if( i_seekpoint != p_access->info.i_seekpoint )
326 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
327 (long unsigned int) i_seekpoint );
328 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
329 p_access->info.i_seekpoint = i_seekpoint;
337 /*****************************************************************************
338 VCDPlay: set up internal structures so seeking/reading places an item.
339 itemid: the thing to play.
340 user_entry: true if itemid is a user selection (rather than internally-
341 generated selection such as via PBC) in which case we may have to adjust
342 for differences in numbering.
343 *****************************************************************************/
345 VCDPlay( access_t *p_access, vcdinfo_itemid_t itemid )
347 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
351 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
353 const vlc_bool_t b_was_still = p_vcd->in_still;
356 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
357 itemid.num, itemid.type);
359 switch (itemid.type) {
360 case VCDINFO_ITEM_TYPE_TRACK:
363 track_t i_track = itemid.num;
364 unsigned int i_entry =
365 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
367 /* Valid MPEG tracks go from 1...i_tracks. */
369 if (i_track == 0 || i_track > p_vcd->i_tracks) {
370 LOG_ERR ("Invalid track number %d", i_track );
373 p_vcd->in_still = VLC_FALSE;
374 VCDSetOrigin( p_access,
375 vcdinfo_get_track_lba(p_vcd->vcd, i_track),
376 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
377 vcdinfo_get_track_lba(p_vcd->vcd, i_track+1),
382 case VCDINFO_ITEM_TYPE_SEGMENT:
384 int i_seg = itemid.num;
386 /* Valid segments go from 0...i_segments-1. */
387 if (itemid.num >= p_vcd->i_segments) {
388 LOG_ERR ( "Invalid segment number: %d", i_seg );
391 vcdinfo_video_segment_type_t segtype =
392 vcdinfo_get_video_type(p_vcd->vcd, i_seg);
394 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
395 vcdinfo_video_type2str(p_vcd->vcd, i_seg),
396 (int) segtype, itemid.num);
400 case VCDINFO_FILES_VIDEO_NTSC_STILL:
401 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
402 case VCDINFO_FILES_VIDEO_PAL_STILL:
403 case VCDINFO_FILES_VIDEO_PAL_STILL2:
404 p_vcd->in_still = VLC_TRUE;
407 p_vcd->in_still = VLC_FALSE;
409 VCDSetOrigin( p_access, p_vcd->p_segments[i_seg],
410 p_vcd->p_segments[i_seg],
411 p_vcd->p_segments[i_seg+1],
418 case VCDINFO_ITEM_TYPE_LID:
419 /* LIDs go from 1..i_lids. */
420 if (itemid.num == 0 || itemid.num > p_vcd->i_lids) {
421 LOG_ERR ( "Invalid LID number: %d", itemid.num );
424 p_vcd->i_lid = itemid.num;
425 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
427 switch (p_vcd->pxd.descriptor_type) {
429 case PSD_TYPE_SELECTION_LIST:
430 case PSD_TYPE_EXT_SELECTION_LIST: {
431 vcdinfo_itemid_t trans_itemid;
432 uint16_t trans_itemid_num;
434 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
435 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
436 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
437 p_vcd->loop_count = 1;
438 p_vcd->loop_item = trans_itemid;
439 return VCDPlay( p_access, trans_itemid );
443 case PSD_TYPE_PLAY_LIST: {
444 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
446 return vcdplayer_inc_play_item(p_access)
447 ? VLC_SUCCESS : VLC_EGENERIC;
451 case PSD_TYPE_END_LIST:
452 case PSD_TYPE_COMMAND_LIST:
459 case VCDINFO_ITEM_TYPE_ENTRY:
461 int i_entry = itemid.num;
463 /* Entries go from 0..i_entries-1. */
464 if (itemid.num >= p_vcd->i_entries) {
465 LOG_ERR ("Invalid entry number: %d", i_entry );
468 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i_entry);
469 p_vcd->in_still = VLC_FALSE;
470 VCDSetOrigin( p_access,
471 vcdinfo_get_entry_lba(p_vcd->vcd, i_track),
472 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
473 vcdinfo_get_entry_lba(p_vcd->vcd, i_track+1),
480 LOG_ERR ("unknown entry type" );
484 p_vcd->play_item = itemid;
492 /*****************************************************************************
493 VCDEntryPoints: Reads the information about the entry points on the disc
494 and initializes area information with that.
495 Before calling this track information should have been read in.
496 *****************************************************************************/
498 VCDEntryPoints( access_t * p_access )
500 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
503 access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
504 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcd->vcd);
505 const track_t i_last_track
506 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcd->vcd))
507 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcd->vcd));
510 if (0 == i_entries) {
511 LOG_ERR ("no entires found -- something is wrong" );
515 p_vcd->p_entries = malloc( sizeof( lsn_t ) * i_entries );
517 if( p_vcd->p_entries == NULL )
519 LOG_ERR ("not enough memory for entry points treatment" );
523 p_vcd->i_entries = i_entries;
525 for( i = 0 ; i < i_entries ; i++ )
527 const track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
528 if( i_track <= i_last_track ) {
529 seekpoint_t *s = vlc_seekpoint_New();
532 snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
534 p_vcd->p_entries[i] = vcdinfo_get_entry_lba(p_vcd->vcd, i);
536 s->psz_name = strdup(psz_entry);
538 (p_vcd->p_entries[i] - vcdinfo_get_track_lba(p_vcd->vcd, i_track))
541 dbg_print( INPUT_DBG_MRL,
542 "%s, lsn %d, byte_offset %ld\n",
543 s->psz_name, p_vcd->p_entries[i],
544 (unsigned long int) s->i_byte_offset);
545 TAB_APPEND( p_vcd->p_title[i_track-1]->i_seekpoint,
546 p_vcd->p_title[i_track-1]->seekpoint, s );
549 msg_Warn( p_access, "wrong track number found in entry points" );
551 p_vcd->b_valid_ep = VLC_TRUE;
558 /*****************************************************************************
559 * VCDSegments: Reads the information about the segments the disc.
560 *****************************************************************************/
562 VCDSegments( access_t * p_access )
564 access_vcd_data_t * p_vcd;
566 unsigned int i_segments;
569 p_vcd = (access_vcd_data_t *) p_access->p_sys;
570 i_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
572 #define area p_access->stream.pp_areas
574 /* area 0 is reserved for segments. Set Absolute start offset
576 area[0]->i_plugin_data = 0;
577 input_DelArea( p_access, area[0] );
578 input_AddArea( p_access, 0, 0 );
580 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
581 * (off_t)M2F2_SECTOR_SIZE;
582 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
583 * (off_t)M2F2_SECTOR_SIZE;
585 /* Default Segment */
588 /* i_plugin_data is used to store which entry point is the first
589 of the track (area) */
590 area[0]->i_plugin_data = 0;
592 area[0]->i_part_nb = 0;
594 dbg_print( INPUT_DBG_MRL,
595 "area[0] id: %d, i_start: %lld, i_size: %lld",
596 area[0]->i_id, area[0]->i_start, area[0]->i_size );
598 if (i_segments == 0) return 0;
600 /* We have one additional segment allocated so we can get the size
601 by subtracting seg[i+1] - seg[i].
603 p_vcd->p_segments = malloc( sizeof( lsn_t ) * (i_segments+1) );
604 if( p_vcd->p_segments == NULL )
606 LOG_ERR ("not enough memory for segment treatment" );
610 /* Update the navigation variables without triggering a callback */
611 VCDUpdateVar( p_access, 0, VLC_VAR_SETVALUE, "title", _("Track"),
614 var_Change( p_access, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
616 for( i = 0 ; i < i_segments ; i++ )
618 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
619 area[0]->i_part_nb ++;
620 VCDUpdateVar( p_access, i , VLC_VAR_ADDCHOICE,
621 "chapter", _("Segment"), "Adding segment choice");
626 p_vcd->p_segments[i_segments] = p_vcd->p_segments[i_segments-1]+
627 vcdinfo_get_seg_sector_count(p_vcd->vcd, i_segments-1);
633 /*****************************************************************************
634 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
636 We start area addressing for tracks at 1 since the default area 0
637 is reserved for segments.
638 *****************************************************************************/
640 VCDTitles( access_t * p_access )
642 /* We'll assume a VCD has its first MPEG track
643 cdio_get_first_track_num()+1 could be used if one wanted to be
644 very careful about this. Note: cdio_get_first_track() will give the
645 ISO-9660 track before the MPEG tracks.
648 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
651 access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
655 for( i = 1 ; i <= p_vcd->i_tracks ; i++ )
657 input_title_t *t = p_vcd->p_title[i-1] = vlc_input_title_New();
659 uint32_t i_secsize = vcdinfo_get_track_sect_count( p_vcd->vcd, i );
661 snprintf( psz_track, sizeof(psz_track), "%s%02d", _("Track "),
664 t->i_size = (i_secsize) * (int64_t) M2F2_SECTOR_SIZE;
665 t->psz_name = strdup(psz_track);
667 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld",
677 /*****************************************************************************
678 VCDLIDs: Reads the LIST IDs from the LOT.
679 *****************************************************************************/
681 VCDLIDs( access_t * p_access )
683 access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
685 p_vcd->i_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
686 p_vcd->i_lid = VCDINFO_INVALID_ENTRY;
688 if (vcdinfo_read_psd (p_vcd->vcd)) {
690 vcdinfo_visit_lot (p_vcd->vcd, VLC_FALSE);
694 We need to change libvcdinfo to be more robust when there are
695 problems reading the extended PSD. Given that area-highlighting and
696 selection features in the extended PSD haven't been implemented,
697 it's best then to not try to read this at all.
699 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
700 vcdinfo_visit_lot (p_vcd->vcd, VLC_TRUE);
704 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
705 "num LIDs=%d", p_vcd->i_lids);
710 /*****************************************************************************
711 * VCDParse: parse command line
712 *****************************************************************************/
714 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
715 /*out*/ vlc_bool_t *play_single_item )
717 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_access->p_sys;
722 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
723 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
725 *play_single_item = VLC_FALSE;
729 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
734 /* On Win32 we want the VCD access plugin to be explicitly requested,
735 * we end up with lots of problems otherwise */
736 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
739 if( !p_access->psz_path )
744 psz_parser = psz_source = strdup( p_access->psz_path );
746 /* Parse input string :
747 * [device][@[type][title]] */
748 while( *psz_parser && *psz_parser != '@' )
753 if( *psz_parser == '@' )
755 /* Found the divide between the source name and the
756 type+entry number. */
763 switch(*psz_parser) {
765 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
767 *play_single_item = VLC_TRUE;
770 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
772 *play_single_item = VLC_FALSE;
775 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
777 *play_single_item = VLC_TRUE;
780 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
782 *play_single_item = VLC_TRUE;
788 num = strtol( psz_parser, &psz_next, 10 );
789 if ( *psz_parser != '\0' && *psz_next == '\0')
795 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
801 /* No source specified, so figure it out. */
802 if( !p_access->psz_access ) return NULL;
804 psz_source = config_GetPsz( p_access, "vcd" );
806 if( !psz_source || 0==strlen(psz_source) ) {
807 /* Scan for a CD-ROM drive with a VCD in it. */
808 char **cd_drives = cdio_get_devices_with_cap( NULL,
809 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
810 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
812 if( NULL == cd_drives ) return NULL;
813 if( cd_drives[0] == NULL )
815 cdio_free_device_list( cd_drives );
818 psz_source = strdup( cd_drives[0] );
819 cdio_free_device_list( cd_drives );
823 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
824 "source=%s entry=%d type=%d",
825 psz_source, p_itemid->num, p_itemid->type);
831 Set's start origin subsequent seeks/reads
834 VCDSetOrigin( access_t *p_access, lsn_t origin_lsn,
835 lsn_t i_lsn, lsn_t end_lsn, track_t i_track,
836 const vcdinfo_itemid_t *p_itemid )
838 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
840 unsigned int i_title = i_track - 1; /* For now */
842 p_vcd->origin_lsn = origin_lsn;
843 p_vcd->i_lsn = i_lsn;
844 p_vcd->end_lsn = end_lsn;
845 p_vcd->i_track = i_track;
846 p_vcd->play_item.num = p_itemid->num;
847 p_vcd->play_item.type = p_itemid->type;
849 p_access->info.i_title = i_track-1;
850 p_access->info.i_size = p_vcd->p_title[i_title]->i_size;
851 p_access->info.i_pos = ( i_lsn - origin_lsn ) * M2F2_SECTOR_SIZE;
852 p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
853 | INPUT_UPDATE_SEEKPOINT;
855 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
856 "origin: %lu, cur_lsn: %lu, end_lsn: %lu, track: %d",
857 (long unsigned int) origin_lsn,
858 (long unsigned int) i_lsn,
859 (long unsigned int) end_lsn, i_track );
861 if (p_itemid->type == VCDINFO_ITEM_TYPE_ENTRY) {
862 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
863 "chapter", _("Entry"), "Setting entry/segment");
864 p_access->info.i_seekpoint = p_itemid->num;
866 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
867 "chapter", _("Segment"), "Setting entry/segment");
868 /* seekpoint is what? ??? */
872 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
873 + strlen(p_vcd->psz_source) + sizeof("@E999")+3;
874 char *psz_mrl = malloc( psz_mrl_max );
879 snprintf(psz_mrl, psz_mrl_max, "%s%s",
880 VCD_MRL_PREFIX, p_vcd->psz_source);
881 psz_name = VCDFormatStr( p_access, p_vcd,
882 config_GetPsz( p_access, MODULE_STRING
884 psz_mrl, &(p_vcd->play_item) );
885 input_Control( p_vcd->p_input, INPUT_SET_NAME, psz_name );
892 /*****************************************************************************
893 * vcd_Open: Opens a VCD device or file and returns an opaque handle
894 *****************************************************************************/
895 static vcdinfo_obj_t *
896 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
898 vcdinfo_obj_t *p_vcdobj;
901 if( !psz_dev ) return NULL;
903 actual_dev=strdup(psz_dev);
904 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
914 /****************************************************************************
915 * VCDReadSector: Read a sector (2324 bytes)
916 ****************************************************************************/
918 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
919 lsn_t i_lsn, byte_t * p_buffer )
922 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
923 uint8_t data [M2F2_SECTOR_SIZE];
926 vcdsector_t vcd_sector;
928 if( cdio_read_mode2_sector( vcdinfo_get_cd_image( p_vcd ),
929 &vcd_sector, i_lsn, VLC_TRUE )
932 msg_Warn( p_this, "Could not read LSN %lu",
933 (long unsigned int) i_lsn );
937 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
942 /****************************************************************************
943 Update the "varname" variable to i_num without triggering a callback.
944 ****************************************************************************/
946 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
947 const char *p_varname, char *p_label,
948 const char *p_debug_label)
953 const access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
954 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
958 text.psz_string = p_label;
959 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
961 var_Change( p_access, p_varname, i_action, &val, NULL );
965 /*****************************************************************************
967 *****************************************************************************/
969 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
970 vlc_value_t oldval, vlc_value_t val, void *p_data )
972 access_vcd_data_t *p_vcd;
974 if (NULL == p_vcd_access) return VLC_EGENERIC;
976 p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
978 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
979 msg_Dbg( p_vcd_access, "Old debug (x%0x) %d, new debug (x%0x) %d",
980 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
982 p_vcd->i_debug = val.i_int;
987 /*****************************************************************************
989 read in meta-information about VCD: the number of tracks, segments,
990 entries, size and starting information. Then set up state variables so
991 that we read/seek starting at the location specified.
993 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
994 and VLC_EGENERIC for some other error.
995 *****************************************************************************/
997 E_(VCDOpen) ( vlc_object_t *p_this )
999 access_t * p_access = (access_t *)p_this;
1000 access_vcd_data_t * p_vcd;
1002 vcdinfo_itemid_t itemid;
1003 vlc_bool_t b_play_ok;
1004 vlc_bool_t play_single_item = VLC_FALSE;
1006 p_access->pf_read = NULL;
1007 p_access->pf_block = VCDReadBlock;
1008 p_access->pf_control = VCDControl;
1009 p_access->pf_seek = VCDSeek;
1011 p_access->info.i_update = 0;
1012 p_access->info.i_size = 0;
1013 p_access->info.i_pos = 0;
1014 p_access->info.b_eof = VLC_FALSE;
1015 p_access->info.i_title = 0;
1016 p_access->info.i_seekpoint = 0;
1018 p_vcd = malloc( sizeof(access_vcd_data_t) );
1022 LOG_ERR ("out of memory" );
1026 p_access->p_sys = (access_sys_t *) p_vcd;
1028 /* Set where to log errors messages from libcdio. */
1029 p_vcd_access = p_access;
1030 cdio_log_set_handler ( cdio_log_handler );
1031 vcd_log_set_handler ( vcd_log_handler );
1033 psz_source = VCDParse( p_access, &itemid, &play_single_item );
1035 if ( NULL == psz_source )
1038 return( VLC_EGENERIC );
1041 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1042 psz_source, p_access->psz_path );
1044 p_vcd->psz_source = strdup(psz_source);
1045 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
1046 p_vcd->in_still = VLC_FALSE;
1047 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
1048 p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT,
1050 p_vcd->p_meta = vlc_meta_New();
1051 p_vcd->p_segments = NULL;
1052 p_vcd->p_entries = NULL;
1056 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1058 msg_Warn( p_access, "could not open %s", psz_source );
1062 p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
1064 /* Get track information. */
1065 p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcd->vcd);
1067 if( p_vcd->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcd->i_tracks ) {
1068 vcdinfo_close( p_vcd->vcd );
1069 LOG_ERR ("no movie tracks found" );
1074 /* Initialize segment information. */
1075 VCDSegments( p_access );
1078 /* Build Navigation Title table. */
1079 VCDTitles( p_access );
1081 /* Map entry points into Chapters */
1082 if( VCDEntryPoints( p_access ) < 0 )
1084 msg_Warn( p_access, "could not read entry points, will not use them" );
1085 p_vcd->b_valid_ep = VLC_FALSE;
1088 if( VCDLIDs( p_access ) < 0 )
1090 msg_Warn( p_access, "could not read entry LIDs" );
1093 b_play_ok = (VLC_SUCCESS == VCDPlay( p_access, itemid ));
1095 if ( ! b_play_ok ) {
1096 vcdinfo_close( p_vcd->vcd );
1100 p_access->psz_demux = strdup( "ps" );
1103 p_vcd->p_intf = intf_Create( p_access, "vcdx" );
1104 p_vcd->p_intf->b_block = VLC_FALSE;
1105 intf_RunThread( p_vcd->p_intf );
1109 if (play_single_item)
1110 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
1121 return VLC_EGENERIC;
1124 /*****************************************************************************
1125 * VCDClose: closes VCD releasing allocated memory.
1126 *****************************************************************************/
1128 E_(VCDClose) ( vlc_object_t *p_this )
1130 access_t *p_access = (access_t *)p_this;
1131 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_access->p_sys;
1133 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1135 vcdinfo_close( p_vcd->vcd );
1137 free( p_vcd->p_entries );
1138 free( p_vcd->p_segments );
1139 free( p_vcd->psz_source );
1141 /* For reasons that are a mystery to me we don't have to deal with
1142 stopping, and destroying the p_vcd->p_intf thread. And if we do
1143 it causes problems upstream.
1145 if( p_vcd->p_intf != NULL )
1147 p_vcd->p_intf = NULL;
1151 p_access->p_sys = NULL;
1152 p_vcd_access = NULL;
1155 /*****************************************************************************
1156 * Control: The front-end or vlc engine calls here to ether get
1157 * information such as meta information or plugin capabilities or to
1158 * issue miscellaneous "set" requests.
1159 *****************************************************************************/
1160 static int VCDControl( access_t *p_access, int i_query, va_list args )
1162 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
1166 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1167 "query %d", i_query );
1171 /* Pass back a copy of meta information that was gathered when we
1172 during the Open/Initialize call.
1174 case ACCESS_GET_META:
1176 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1178 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1180 if ( p_vcd->p_meta ) {
1181 *pp_meta = vlc_meta_Duplicate( p_vcd->p_meta );
1182 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1184 msg_Warn( p_access, "tried to copy NULL meta info" );
1188 return VLC_EGENERIC;
1190 case ACCESS_CAN_SEEK:
1191 case ACCESS_CAN_FASTSEEK:
1192 case ACCESS_CAN_PAUSE:
1193 case ACCESS_CAN_CONTROL_PACE:
1195 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1197 dbg_print( INPUT_DBG_EVENT,
1198 "seek/fastseek/pause/can_control_pace" );
1199 *pb_bool = VLC_TRUE;
1205 case ACCESS_GET_MTU:
1206 pi_int = (int*)va_arg( args, int * );
1207 *pi_int = (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE);
1208 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1211 case ACCESS_GET_PTS_DELAY:
1213 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1214 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1215 * MILLISECONDS_PER_SEC;
1216 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1222 case ACCESS_SET_PAUSE_STATE:
1223 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1227 case ACCESS_GET_TITLE_INFO:
1229 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1230 + strlen(p_vcd->psz_source) + sizeof("@E999")+3;
1231 input_title_t ***ppp_title
1232 = (input_title_t***)va_arg( args, input_title_t*** );
1233 char *psz_mrl = malloc( psz_mrl_max );
1236 pi_int = (int*)va_arg( args, int* );
1238 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1241 if( psz_mrl == NULL ) {
1242 msg_Warn( p_access, "out of memory" );
1244 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1245 VCD_MRL_PREFIX, p_vcd->psz_source);
1246 VCDMetaInfo( p_access, psz_mrl );
1250 /* Duplicate title info */
1251 if( p_vcd->i_titles == 0 )
1253 *pi_int = 0; ppp_title = NULL;
1256 *pi_int = p_vcd->i_titles;
1257 *ppp_title = malloc(sizeof( input_title_t **) * p_vcd->i_titles );
1259 if (!*ppp_title) return VLC_ENOMEM;
1261 for( i = 0; i < p_vcd->i_titles; i++ )
1263 if ( p_vcd->p_title[i] )
1265 vlc_input_title_Duplicate( p_vcd->p_title[i] );
1270 case ACCESS_SET_TITLE:
1271 i = (int)va_arg( args, int );
1273 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1274 if( i != p_access->info.i_title )
1276 vcdinfo_itemid_t itemid;
1277 track_t i_track = i+1;
1278 unsigned int i_entry =
1279 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
1281 /* FIXME! For now we are assuming titles are only
1282 tracks and that track == title+1 */
1283 itemid.num = i_track;
1284 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1286 VCDSetOrigin(p_access,
1287 vcdinfo_get_track_lba(p_vcd->vcd, i_track),
1288 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
1289 vcdinfo_get_track_lba(p_vcd->vcd, i_track+1),
1294 case ACCESS_SET_SEEKPOINT:
1296 input_title_t *t = p_vcd->p_title[p_access->info.i_title];
1297 i = (int)va_arg( args, int );
1299 dbg_print( INPUT_DBG_EVENT, "set seekpoint" );
1300 if( t->i_seekpoint > 0 )
1302 track_t i_track = p_access->info.i_title+1;
1304 /* FIXME! For now we are assuming titles are only
1305 tracks and that track == title+1 and we the play
1306 item is entries (not tracks or lids).
1307 We need to generalize all of this.
1310 p_vcd->play_item.num = i;
1311 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1313 VCDSetOrigin( p_access,
1314 vcdinfo_get_track_lba(p_vcd->vcd, i_track),
1315 vcdinfo_get_entry_lba(p_vcd->vcd, i),
1316 vcdinfo_get_track_lba(p_vcd->vcd, i_track+1),
1317 i_track, &(p_vcd->play_item) );
1322 case ACCESS_SET_PRIVATE_ID_STATE:
1323 dbg_print( INPUT_DBG_EVENT, "set private id" );
1324 return VLC_EGENERIC;
1327 msg_Warn( p_access, "unimplemented query in control" );
1328 return VLC_EGENERIC;