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 #define FREE_AND_NULL(ptr) if (NULL != ptr) free(ptr); ptr = NULL;
50 /*****************************************************************************
52 *****************************************************************************/
54 /* First those which are accessed from outside (via pointers). */
55 static block_t *VCDReadBlock ( access_t * );
57 static int VCDControl ( access_t *p_access, int i_query,
60 /* Now those which are strictly internal */
61 static void VCDSetOrigin ( access_t *p_access, lsn_t i_lsn,
63 const vcdinfo_itemid_t * p_itemid );
64 static int VCDEntryPoints ( access_t * );
65 static int VCDLIDs ( access_t * );
67 static int VCDSegments ( access_t * );
69 static int VCDTitles ( access_t * );
70 static int VCDReadSector ( vlc_object_t *p_this,
71 const vcdinfo_obj_t *p_vcd, lsn_t i_lsn,
73 static char *VCDParse ( access_t *,
74 /*out*/ vcdinfo_itemid_t * p_itemid ,
75 /*out*/ vlc_bool_t *play_single_item );
77 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
78 const char *p_varname, char *p_label,
79 const char *p_debug_label );
81 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
83 /****************************************************************************
85 ****************************************************************************/
87 /* FIXME: This variable is a hack. Would be nice to eliminate the
90 static access_t *p_vcd_access = NULL;
92 /* process messages that originate from libcdio. */
94 cdio_log_handler (cdio_log_level_t level, const char message[])
96 const vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
100 if (p_vcd->i_debug & INPUT_DBG_CDIO)
101 msg_Dbg( p_vcd_access, message);
104 msg_Warn( p_vcd_access, message);
107 case CDIO_LOG_ASSERT:
108 msg_Err( p_vcd_access, message);
111 msg_Warn( p_vcd_access, message,
112 _("The above message had unknown log level"),
118 /* process messages that originate from vcdinfo. */
120 vcd_log_handler (vcd_log_level_t level, const char message[])
122 vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
126 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
127 msg_Dbg( p_vcd_access, message);
130 msg_Warn( p_vcd_access, message);
134 msg_Err( p_vcd_access, message);
137 msg_Warn( p_vcd_access, "%s\n%s %d", message,
138 _("The above message had unknown vcdimager log level"),
144 /*****************************************************************************
145 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
146 NULL is returned if something went wrong.
147 *****************************************************************************/
149 VCDReadBlock( access_t * p_access )
151 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
153 const int i_blocks = p_vcd->i_blocks_per_read;
155 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
160 dbg_print( (INPUT_DBG_CALL), "lsn: %lu",
161 (long unsigned int) p_vcd->i_lsn );
164 /* Allocate a block for the reading */
165 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
167 msg_Err( p_access, "cannot get a new block of size: %i",
168 i_blocks * M2F2_SECTOR_SIZE );
169 block_Release( p_block );
173 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
176 if ( p_vcd->i_lsn >= p_vcd->end_lsn ) {
177 vcdplayer_read_status_t read_status;
179 /* We've run off of the end of this entry. Do we continue or stop? */
180 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
181 "end reached, cur: %lu, end: %u",
182 (long unsigned int) p_vcd->i_lsn,
185 read_status = vcdplayer_pbc_is_on( p_vcd )
186 ? vcdplayer_pbc_nav( p_access )
187 : vcdplayer_non_pbc_nav( p_access );
189 switch (read_status) {
191 /* End reached. Return NULL to indicated this. */
193 /* Some sort of error. */
196 case READ_STILL_FRAME:
198 /* Reached the end of a still frame. */
199 byte_t * p_buf = (byte_t *) p_block->p_buffer;
201 p_buf += (i_read*M2F2_SECTOR_SIZE);
202 memset(p_buf, 0, M2F2_SECTOR_SIZE);
205 dbg_print(INPUT_DBG_STILL, "Handled still event");
207 p_vcd->p_intf->p_sys->b_still = VLC_TRUE;
208 var_SetInteger( p_access, "state", PAUSE_S );
218 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
220 (byte_t *) p_block->p_buffer
221 + (i_read*M2F2_SECTOR_SIZE) ) < 0 )
223 LOG_ERR ("could not read sector %lu",
224 (long unsigned int) p_vcd->i_lsn );
225 /* Try to skip one sector (in case of bad sectors) */
227 p_access->info.i_pos += M2F2_SECTOR_SIZE;
232 p_access->info.i_pos += M2F2_SECTOR_SIZE;
234 /* Update seekpoint */
235 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type )
237 unsigned int i_entry = p_vcd->play_item.num+1;
239 if (p_vcd->i_lsn >= vcdinfo_get_entry_lba(p_vcd->vcd, i_entry))
241 const track_t i_track = p_vcd->i_track;
242 p_vcd->play_item.num = i_entry;
243 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "entry change" );
244 VCDSetOrigin( p_access,
245 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
246 i_track, &(p_vcd->play_item) );
251 if ( i_read != i_blocks ) /* this should not happen */
253 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
254 p_vcd->i_lsn, p_last_sector ) < 0 )
256 LOG_ERR ("could not read sector %lu",
257 (long unsigned int) p_vcd->i_lsn );
268 /****************************************************************************
270 ****************************************************************************/
272 VCDSeek( access_t * p_access, int64_t i_pos )
274 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
277 vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
278 const input_title_t *t = p_vcd->p_title[p_access->info.i_title];
280 unsigned int i_entry=VCDINFO_INVALID_ENTRY;
282 /* Next sector to read */
283 p_access->info.i_pos = i_pos;
284 p_vcd->i_lsn = (i_pos / (int64_t)M2F2_SECTOR_SIZE) +
288 if( p_vcd->b_valid_ep )
290 for( i_entry = 0 ; i_entry < p_vcd->i_entries ; i_entry ++ )
292 if( p_vcd->i_lsn < p_vcd->p_entries[i_entry] )
294 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
295 "chapter", _("Entry"), "Setting entry" );
299 p_vcd->play_item.num = i_entry;
300 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
301 vcdplayer_set_origin(p_access);
302 VCDUpdateTitle(p_access);
305 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
306 "orig %lu, cur: %lu, offset: %lld, entry %d",
307 (long unsigned int) p_vcd->origin_lsn,
308 (long unsigned int) p_vcd->i_lsn, i_pos,
312 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
314 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
315 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
318 /* Update current seekpoint */
319 if( i_seekpoint != p_access->info.i_seekpoint )
321 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
322 (long unsigned int) i_seekpoint );
323 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
324 p_access->info.i_seekpoint = i_seekpoint;
332 /*****************************************************************************
333 VCDPlay: set up internal structures so seeking/reading places an item.
334 itemid: the thing to play.
335 user_entry: true if itemid is a user selection (rather than internally-
336 generated selection such as via PBC) in which case we may have to adjust
337 for differences in numbering.
338 *****************************************************************************/
340 VCDPlay( access_t *p_access, vcdinfo_itemid_t itemid )
342 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
346 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
348 const vlc_bool_t b_was_still = p_vcd->in_still;
351 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
352 itemid.num, itemid.type);
354 switch (itemid.type) {
355 case VCDINFO_ITEM_TYPE_TRACK:
358 track_t i_track = itemid.num;
359 unsigned int i_entry =
360 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
362 /* Valid MPEG tracks go from 1...i_tracks. */
364 if (i_track == 0 || i_track > p_vcd->i_tracks) {
365 LOG_ERR ("Invalid track number %d", i_track );
368 p_vcd->in_still = VLC_FALSE;
369 VCDSetOrigin( p_access,
370 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
375 case VCDINFO_ITEM_TYPE_SEGMENT:
377 int i_seg = itemid.num;
379 /* Valid segments go from 0...i_segments-1. */
380 if (itemid.num >= p_vcd->i_segments) {
381 LOG_ERR ( "Invalid segment number: %d", i_seg );
384 vcdinfo_video_segment_type_t segtype =
385 vcdinfo_get_video_type(p_vcd->vcd, i_seg);
387 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
388 vcdinfo_video_type2str(p_vcd->vcd, i_seg),
389 (int) segtype, itemid.num);
393 case VCDINFO_FILES_VIDEO_NTSC_STILL:
394 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
395 case VCDINFO_FILES_VIDEO_PAL_STILL:
396 case VCDINFO_FILES_VIDEO_PAL_STILL2:
397 p_vcd->in_still = VLC_TRUE;
400 p_vcd->in_still = VLC_FALSE;
402 VCDSetOrigin( p_access, p_vcd->p_segments[i_seg],
409 case VCDINFO_ITEM_TYPE_LID:
410 /* LIDs go from 1..i_lids. */
411 if (itemid.num == 0 || itemid.num > p_vcd->i_lids) {
412 LOG_ERR ( "Invalid LID number: %d", itemid.num );
415 p_vcd->i_lid = itemid.num;
416 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
418 switch (p_vcd->pxd.descriptor_type) {
420 case PSD_TYPE_SELECTION_LIST:
421 case PSD_TYPE_EXT_SELECTION_LIST: {
422 vcdinfo_itemid_t trans_itemid;
423 uint16_t trans_itemid_num;
425 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
426 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
427 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
428 p_vcd->loop_count = 1;
429 p_vcd->loop_item = trans_itemid;
430 return VCDPlay( p_access, trans_itemid );
434 case PSD_TYPE_PLAY_LIST: {
435 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
437 return vcdplayer_inc_play_item(p_access)
438 ? VLC_SUCCESS : VLC_EGENERIC;
442 case PSD_TYPE_END_LIST:
443 case PSD_TYPE_COMMAND_LIST:
450 case VCDINFO_ITEM_TYPE_ENTRY:
452 int i_entry = itemid.num;
454 /* Entries go from 0..i_entries-1. */
455 if (itemid.num >= p_vcd->i_entries) {
456 LOG_ERR ("Invalid entry number: %d", i_entry );
459 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i_entry);
460 p_vcd->in_still = VLC_FALSE;
461 VCDSetOrigin( p_access,
462 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
469 LOG_ERR ("unknown entry type" );
473 p_vcd->play_item = itemid;
481 /*****************************************************************************
482 VCDEntryPoints: Reads the information about the entry points on the disc
483 and initializes area information with that.
484 Before calling this track information should have been read in.
485 *****************************************************************************/
487 VCDEntryPoints( access_t * p_access )
489 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
492 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
493 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcd->vcd);
494 const track_t i_last_track
495 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcd->vcd))
496 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcd->vcd));
499 if (0 == i_entries) {
500 LOG_ERR ("no entires found -- something is wrong" );
504 p_vcd->p_entries = malloc( sizeof( lsn_t ) * i_entries );
506 if( p_vcd->p_entries == NULL )
508 LOG_ERR ("not enough memory for entry points treatment" );
512 p_vcd->i_entries = i_entries;
514 for( i = 0 ; i < i_entries ; i++ )
516 const track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
517 if( i_track <= i_last_track ) {
518 seekpoint_t *s = vlc_seekpoint_New();
521 snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
523 p_vcd->p_entries[i] = vcdinfo_get_entry_lba(p_vcd->vcd, i);
525 s->psz_name = strdup(psz_entry);
527 (p_vcd->p_entries[i] - vcdinfo_get_track_lba(p_vcd->vcd, i_track))
530 dbg_print( INPUT_DBG_MRL,
531 "%s, lsn %d, byte_offset %ld\n",
532 s->psz_name, p_vcd->p_entries[i],
533 (unsigned long int) s->i_byte_offset);
534 TAB_APPEND( p_vcd->p_title[i_track-1]->i_seekpoint,
535 p_vcd->p_title[i_track-1]->seekpoint, s );
538 msg_Warn( p_access, "wrong track number found in entry points" );
540 p_vcd->b_valid_ep = VLC_TRUE;
547 /*****************************************************************************
548 * VCDSegments: Reads the information about the segments the disc.
549 *****************************************************************************/
551 VCDSegments( access_t * p_access )
555 unsigned int i_segments;
558 p_vcd = (vcdplayer_t *) p_access->p_sys;
559 i_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
561 #define area p_access->stream.pp_areas
563 /* area 0 is reserved for segments. Set Absolute start offset
565 area[0]->i_plugin_data = 0;
566 input_DelArea( p_access, area[0] );
567 input_AddArea( p_access, 0, 0 );
569 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
570 * (off_t)M2F2_SECTOR_SIZE;
571 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
572 * (off_t)M2F2_SECTOR_SIZE;
574 /* Default Segment */
577 /* i_plugin_data is used to store which entry point is the first
578 of the track (area) */
579 area[0]->i_plugin_data = 0;
581 area[0]->i_part_nb = 0;
583 dbg_print( INPUT_DBG_MRL,
584 "area[0] id: %d, i_start: %lld, i_size: %lld",
585 area[0]->i_id, area[0]->i_start, area[0]->i_size );
587 if (i_segments == 0) return 0;
589 /* We have one additional segment allocated so we can get the size
590 by subtracting seg[i+1] - seg[i].
592 p_vcd->p_segments = malloc( sizeof( lsn_t ) * (i_segments+1) );
593 if( p_vcd->p_segments == NULL )
595 LOG_ERR ("not enough memory for segment treatment" );
599 /* Update the navigation variables without triggering a callback */
600 VCDUpdateVar( p_access, 0, VLC_VAR_SETVALUE, "title", _("Track"),
603 var_Change( p_access, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
605 for( i = 0 ; i < i_segments ; i++ )
607 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
608 area[0]->i_part_nb ++;
609 VCDUpdateVar( p_access, i , VLC_VAR_ADDCHOICE,
610 "chapter", _("Segment"), "Adding segment choice");
615 p_vcd->p_segments[i_segments] = p_vcd->p_segments[i_segments-1]+
616 vcdinfo_get_seg_sector_count(p_vcd->vcd, i_segments-1);
622 /*****************************************************************************
623 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
625 We start area addressing for tracks at 1 since the default area 0
626 is reserved for segments.
627 *****************************************************************************/
629 VCDTitles( access_t * p_access )
631 /* We'll assume a VCD has its first MPEG track
632 cdio_get_first_track_num()+1 could be used if one wanted to be
633 very careful about this. Note: cdio_get_first_track() will give the
634 ISO-9660 track before the MPEG tracks.
637 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
640 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
644 for( i = 1 ; i <= p_vcd->i_tracks ; i++ )
646 input_title_t *t = p_vcd->p_title[i-1] = vlc_input_title_New();
648 uint32_t i_secsize = vcdinfo_get_track_sect_count( p_vcd->vcd, i );
650 snprintf( psz_track, sizeof(psz_track), "%s%02d", _("Track "),
653 t->i_size = (i_secsize) * (int64_t) M2F2_SECTOR_SIZE;
654 t->psz_name = strdup(psz_track);
656 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld",
666 /*****************************************************************************
667 VCDLIDs: Reads the LIST IDs from the LOT.
668 *****************************************************************************/
670 VCDLIDs( access_t * p_access )
672 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
674 p_vcd->i_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
675 p_vcd->i_lid = VCDINFO_INVALID_ENTRY;
677 if (vcdinfo_read_psd (p_vcd->vcd)) {
679 vcdinfo_visit_lot (p_vcd->vcd, VLC_FALSE);
683 We need to change libvcdinfo to be more robust when there are
684 problems reading the extended PSD. Given that area-highlighting and
685 selection features in the extended PSD haven't been implemented,
686 it's best then to not try to read this at all.
688 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
689 vcdinfo_visit_lot (p_vcd->vcd, VLC_TRUE);
693 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
694 "num LIDs=%d", p_vcd->i_lids);
699 /*****************************************************************************
700 * VCDParse: parse command line
701 *****************************************************************************/
703 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
704 /*out*/ vlc_bool_t *play_single_item )
706 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
711 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
712 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
714 *play_single_item = VLC_FALSE;
718 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
723 /* On Win32 we want the VCD access plugin to be explicitly requested,
724 * we end up with lots of problems otherwise */
725 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
728 if( !p_access->psz_path )
733 psz_parser = psz_source = strdup( p_access->psz_path );
735 /* Parse input string :
736 * [device][@[type][title]] */
737 while( *psz_parser && *psz_parser != '@' )
742 if( *psz_parser == '@' )
744 /* Found the divide between the source name and the
745 type+entry number. */
752 switch(*psz_parser) {
754 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
756 *play_single_item = VLC_TRUE;
759 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
761 *play_single_item = VLC_FALSE;
764 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
766 *play_single_item = VLC_TRUE;
769 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
771 *play_single_item = VLC_TRUE;
777 num = strtol( psz_parser, &psz_next, 10 );
778 if ( *psz_parser != '\0' && *psz_next == '\0')
784 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
790 /* No source specified, so figure it out. */
791 if( !p_access->psz_access ) return NULL;
793 psz_source = config_GetPsz( p_access, "vcd" );
795 if( !psz_source || 0==strlen(psz_source) ) {
796 /* Scan for a CD-ROM drive with a VCD in it. */
797 char **cd_drives = cdio_get_devices_with_cap( NULL,
798 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
799 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
801 if( NULL == cd_drives ) return NULL;
802 if( cd_drives[0] == NULL )
804 cdio_free_device_list( cd_drives );
807 psz_source = strdup( cd_drives[0] );
808 cdio_free_device_list( cd_drives );
812 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
813 "source=%s entry=%d type=%d",
814 psz_source, p_itemid->num, p_itemid->type);
820 Set's start origin subsequent seeks/reads
823 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
824 const vcdinfo_itemid_t *p_itemid )
826 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
828 unsigned int i_title = i_track - 1; /* For now */
830 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
831 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
834 p_vcd->i_lsn = i_lsn;
835 p_vcd->i_track = i_track;
836 p_vcd->track_lsn = vcdinfo_get_track_lsn(p_vcd->vcd, i_track);
838 p_vcd->play_item.num = p_itemid->num;
839 p_vcd->play_item.type = p_itemid->type;
841 vcdplayer_set_origin(p_access);
843 p_access->info.i_title = i_track-1;
844 p_access->info.i_size = p_vcd->p_title[i_title]->i_size;
845 p_access->info.i_pos = ( i_lsn - p_vcd->track_lsn )
847 p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
848 | INPUT_UPDATE_SEEKPOINT;
850 if (p_itemid->type == VCDINFO_ITEM_TYPE_ENTRY) {
851 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
852 "chapter", _("Entry"), "Setting entry/segment");
853 p_access->info.i_seekpoint = p_itemid->num;
855 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
856 "chapter", _("Segment"), "Setting entry/segment");
857 /* seekpoint is what? ??? */
860 VCDUpdateTitle( p_access );
864 /*****************************************************************************
865 * vcd_Open: Opens a VCD device or file initializes, a list of
866 tracks, segements and entry lsns and sizes and returns an opaque handle.
867 *****************************************************************************/
868 static vcdinfo_obj_t *
869 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
871 access_t *p_access = (access_t *)p_this;
872 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
873 vcdinfo_obj_t *p_vcdobj;
877 dbg_print(INPUT_DBG_CALL, "called with %s\n", psz_dev);
879 if( !psz_dev ) return NULL;
881 actual_dev=strdup(psz_dev);
882 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
890 Save summary info on tracks, segments and entries...
893 if ( 0 < (p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
894 p_vcd->track = (vcdplayer_play_item_info_t *)
895 calloc(p_vcd->i_tracks, sizeof(vcdplayer_play_item_info_t));
897 for (i=0; i<p_vcd->i_tracks; i++) {
898 unsigned int track_num=i+1;
899 p_vcd->track[i].size =
900 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
901 p_vcd->track[i].start_LSN =
902 vcdinfo_get_track_lsn(p_vcdobj, track_num);
907 if ( 0 < (p_vcd->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
908 p_vcd->entry = (vcdplayer_play_item_info_t *)
909 calloc(p_vcd->i_entries, sizeof(vcdplayer_play_item_info_t));
911 for (i=0; i<p_vcd->i_entries; i++) {
912 p_vcd->entry[i].size = vcdinfo_get_entry_sect_count(p_vcdobj, i);
913 p_vcd->entry[i].start_LSN = vcdinfo_get_entry_lba(p_vcdobj, i);
918 if ( 0 < (p_vcd->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
919 p_vcd->segment = (vcdplayer_play_item_info_t *)
920 calloc(p_vcd->i_segments, sizeof(vcdplayer_play_item_info_t));
922 for (i=0; i<p_vcd->i_segments; i++) {
923 p_vcd->segment[i].size = vcdinfo_get_seg_sector_count(p_vcdobj, i);
924 p_vcd->segment[i].start_LSN = vcdinfo_get_seg_lba(p_vcdobj, i);
927 p_vcd->segment = NULL;
933 /****************************************************************************
934 * VCDReadSector: Read a sector (2324 bytes)
935 ****************************************************************************/
937 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
938 lsn_t i_lsn, byte_t * p_buffer )
941 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
942 uint8_t data [M2F2_SECTOR_SIZE];
945 vcdsector_t vcd_sector;
947 if( cdio_read_mode2_sector( vcdinfo_get_cd_image( p_vcd ),
948 &vcd_sector, i_lsn, VLC_TRUE )
951 msg_Warn( p_this, "Could not read LSN %lu",
952 (long unsigned int) i_lsn );
956 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
961 /****************************************************************************
962 Update the "varname" variable to i_num without triggering a callback.
963 ****************************************************************************/
965 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
966 const char *p_varname, char *p_label,
967 const char *p_debug_label)
972 const vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
973 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
977 text.psz_string = p_label;
978 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
980 var_Change( p_access, p_varname, i_action, &val, NULL );
984 /*****************************************************************************
986 *****************************************************************************/
988 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
989 vlc_value_t oldval, vlc_value_t val, void *p_data )
993 if (NULL == p_vcd_access) return VLC_EGENERIC;
995 p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
997 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
998 msg_Dbg( p_vcd_access, "Old debug (x%0x) %d, new debug (x%0x) %d",
999 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
1001 p_vcd->i_debug = val.i_int;
1006 E_(BlocksPerReadCallback) ( vlc_object_t *p_this, const char *psz_name,
1007 vlc_value_t oldval, vlc_value_t val,
1012 if (NULL == p_vcd_access) return VLC_EGENERIC;
1014 p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
1016 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
1017 msg_Dbg( p_vcd_access, "Old debug (x%0x) %d, new debug (x%0x) %d",
1018 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
1020 p_vcd->i_debug = val.i_int;
1025 /*****************************************************************************
1027 read in meta-information about VCD: the number of tracks, segments,
1028 entries, size and starting information. Then set up state variables so
1029 that we read/seek starting at the location specified.
1031 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
1032 and VLC_EGENERIC for some other error.
1033 *****************************************************************************/
1035 E_(VCDOpen) ( vlc_object_t *p_this )
1037 access_t *p_access = (access_t *)p_this;
1040 vcdinfo_itemid_t itemid;
1041 vlc_bool_t b_play_ok;
1042 vlc_bool_t play_single_item = VLC_FALSE;
1044 p_access->pf_read = NULL;
1045 p_access->pf_block = VCDReadBlock;
1046 p_access->pf_control = VCDControl;
1047 p_access->pf_seek = VCDSeek;
1049 p_access->info.i_update = 0;
1050 p_access->info.i_size = 0;
1051 p_access->info.i_pos = 0;
1052 p_access->info.b_eof = VLC_FALSE;
1053 p_access->info.i_title = 0;
1054 p_access->info.i_seekpoint = 0;
1056 p_vcd = malloc( sizeof(vcdplayer_t) );
1060 LOG_ERR ("out of memory" );
1064 p_access->p_sys = (access_sys_t *) p_vcd;
1066 /* Set where to log errors messages from libcdio. */
1067 p_vcd_access = p_access;
1068 cdio_log_set_handler ( cdio_log_handler );
1069 vcd_log_set_handler ( vcd_log_handler );
1071 psz_source = VCDParse( p_access, &itemid, &play_single_item );
1073 if ( NULL == psz_source )
1076 return( VLC_EGENERIC );
1079 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1080 psz_source, p_access->psz_path );
1082 p_vcd->psz_source = strdup(psz_source);
1083 p_vcd->i_debug = config_GetInt( p_this,
1084 MODULE_STRING "-debug" );
1085 p_vcd->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
1086 "-blocks-per-read" );
1087 p_vcd->in_still = VLC_FALSE;
1088 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
1089 p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT,
1091 p_vcd->p_meta = vlc_meta_New();
1092 p_vcd->p_segments = NULL;
1093 p_vcd->p_entries = NULL;
1097 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1099 msg_Warn( p_access, "could not open %s", psz_source );
1103 p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
1105 /* Get track information. */
1106 p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcd->vcd);
1108 if( p_vcd->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcd->i_tracks ) {
1109 vcdinfo_close( p_vcd->vcd );
1110 LOG_ERR ("no movie tracks found" );
1115 /* Initialize segment information. */
1116 VCDSegments( p_access );
1119 /* Build Navigation Title table. */
1120 VCDTitles( p_access );
1122 /* Map entry points into Chapters */
1123 if( VCDEntryPoints( p_access ) < 0 )
1125 msg_Warn( p_access, "could not read entry points, will not use them" );
1126 p_vcd->b_valid_ep = VLC_FALSE;
1129 if( VCDLIDs( p_access ) < 0 )
1131 msg_Warn( p_access, "could not read entry LIDs" );
1134 b_play_ok = (VLC_SUCCESS == VCDPlay( p_access, itemid ));
1136 if ( ! b_play_ok ) {
1137 vcdinfo_close( p_vcd->vcd );
1141 p_access->psz_demux = strdup( "ps" );
1144 p_vcd->p_intf = intf_Create( p_access, "vcdx" );
1145 p_vcd->p_intf->b_block = VLC_FALSE;
1146 intf_RunThread( p_vcd->p_intf );
1150 if (play_single_item)
1151 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
1162 return VLC_EGENERIC;
1165 /*****************************************************************************
1166 * VCDClose: closes VCD releasing allocated memory.
1167 *****************************************************************************/
1169 E_(VCDClose) ( vlc_object_t *p_this )
1171 access_t *p_access = (access_t *)p_this;
1172 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
1174 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1176 vcdinfo_close( p_vcd->vcd );
1178 FREE_AND_NULL( p_vcd->p_entries );
1179 FREE_AND_NULL( p_vcd->p_segments );
1180 FREE_AND_NULL( p_vcd->psz_source );
1181 FREE_AND_NULL( p_vcd->track );
1182 FREE_AND_NULL( p_vcd->segment );
1183 FREE_AND_NULL( p_vcd->entry );
1186 p_access->p_sys = NULL;
1187 p_vcd_access = NULL;
1190 /*****************************************************************************
1191 * Control: The front-end or vlc engine calls here to ether get
1192 * information such as meta information or plugin capabilities or to
1193 * issue miscellaneous "set" requests.
1194 *****************************************************************************/
1195 static int VCDControl( access_t *p_access, int i_query, va_list args )
1197 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
1201 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1202 "query %d", i_query );
1206 /* Pass back a copy of meta information that was gathered when we
1207 during the Open/Initialize call.
1209 case ACCESS_GET_META:
1211 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1213 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1215 if ( p_vcd->p_meta ) {
1216 *pp_meta = vlc_meta_Duplicate( p_vcd->p_meta );
1217 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1219 msg_Warn( p_access, "tried to copy NULL meta info" );
1223 return VLC_EGENERIC;
1225 case ACCESS_CAN_SEEK:
1226 case ACCESS_CAN_FASTSEEK:
1227 case ACCESS_CAN_PAUSE:
1228 case ACCESS_CAN_CONTROL_PACE:
1230 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1232 dbg_print( INPUT_DBG_EVENT,
1233 "seek/fastseek/pause/can_control_pace" );
1234 *pb_bool = VLC_TRUE;
1240 case ACCESS_GET_MTU:
1241 pi_int = (int*)va_arg( args, int * );
1242 *pi_int = (p_vcd->i_blocks_per_read * M2F2_SECTOR_SIZE);
1243 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1246 case ACCESS_GET_PTS_DELAY:
1248 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1249 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1250 * MILLISECONDS_PER_SEC;
1251 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1257 case ACCESS_SET_PAUSE_STATE:
1258 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1262 case ACCESS_GET_TITLE_INFO:
1264 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1265 + strlen(p_vcd->psz_source) + sizeof("@E999")+3;
1266 input_title_t ***ppp_title
1267 = (input_title_t***)va_arg( args, input_title_t*** );
1268 char *psz_mrl = malloc( psz_mrl_max );
1271 pi_int = (int*)va_arg( args, int* );
1273 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1276 if( psz_mrl == NULL ) {
1277 msg_Warn( p_access, "out of memory" );
1279 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1280 VCD_MRL_PREFIX, p_vcd->psz_source);
1281 VCDMetaInfo( p_access, psz_mrl );
1285 /* Duplicate title info */
1286 if( p_vcd->i_titles == 0 )
1288 *pi_int = 0; ppp_title = NULL;
1291 *pi_int = p_vcd->i_titles;
1292 *ppp_title = malloc(sizeof( input_title_t **) * p_vcd->i_titles );
1294 if (!*ppp_title) return VLC_ENOMEM;
1296 for( i = 0; i < p_vcd->i_titles; i++ )
1298 if ( p_vcd->p_title[i] )
1300 vlc_input_title_Duplicate( p_vcd->p_title[i] );
1305 case ACCESS_SET_TITLE:
1306 i = (int)va_arg( args, int );
1308 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1309 if( i != p_access->info.i_title )
1311 vcdinfo_itemid_t itemid;
1312 track_t i_track = i+1;
1313 unsigned int i_entry =
1314 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
1316 /* FIXME! For now we are assuming titles are only
1317 tracks and that track == title+1 */
1318 itemid.num = i_track;
1319 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1321 VCDSetOrigin(p_access,
1322 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
1327 case ACCESS_SET_SEEKPOINT:
1329 input_title_t *t = p_vcd->p_title[p_access->info.i_title];
1330 i = (int)va_arg( args, int );
1332 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1333 if( t->i_seekpoint > 0 )
1335 track_t i_track = p_access->info.i_title+1;
1337 /* FIXME! For now we are assuming titles are only
1338 tracks and that track == title+1 and we the play
1339 item is entries (not tracks or lids).
1340 We need to generalize all of this.
1343 p_vcd->play_item.num = i;
1344 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1346 VCDSetOrigin( p_access,
1347 vcdinfo_get_entry_lba(p_vcd->vcd, i),
1348 i_track, &(p_vcd->play_item) );
1353 case ACCESS_SET_PRIVATE_ID_STATE:
1354 dbg_print( INPUT_DBG_EVENT, "set private id" );
1355 return VLC_EGENERIC;
1358 msg_Warn( p_access, "unimplemented query in control" );
1359 return VLC_EGENERIC;