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>
37 #include <cdio/cdio.h>
38 #include <cdio/cd_types.h>
39 #include <cdio/logging.h>
40 #include <cdio/util.h>
41 #include <libvcd/info.h>
42 #include <libvcd/logging.h>
47 #define FREE_AND_NULL(ptr) if (NULL != ptr) free(ptr); ptr = NULL;
49 extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
50 const vcdinfo_itemid_t *p_itemid );
52 /*****************************************************************************
54 *****************************************************************************/
56 /* First those which are accessed from outside (via pointers). */
57 static block_t *VCDReadBlock ( access_t * );
59 static int VCDControl ( access_t *p_access, int i_query,
62 /* Now those which are strictly internal */
63 static vlc_bool_t VCDEntryPoints ( access_t * );
64 static vlc_bool_t VCDLIDs ( access_t * );
65 static vlc_bool_t VCDSegments ( access_t * );
66 static int VCDTitles ( access_t * );
67 static char *VCDParse ( access_t *,
68 /*out*/ vcdinfo_itemid_t * p_itemid ,
69 /*out*/ vlc_bool_t *play_single_item );
71 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
72 const char *p_varname, char *p_label,
73 const char *p_debug_label );
75 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
77 /****************************************************************************
79 ****************************************************************************/
81 /* FIXME: This variable is a hack. Would be nice to eliminate the
84 static access_t *p_vcd_access = NULL;
86 /* process messages that originate from libcdio. */
88 cdio_log_handler (cdio_log_level_t level, const char message[])
90 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
94 if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
95 msg_Dbg( p_vcd_access, message);
98 msg_Warn( p_vcd_access, message);
101 case CDIO_LOG_ASSERT:
102 msg_Err( p_vcd_access, message);
105 msg_Warn( p_vcd_access, message,
106 _("The above message had unknown log level"),
112 /* process messages that originate from vcdinfo. */
114 vcd_log_handler (vcd_log_level_t level, const char message[])
116 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
120 if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
121 msg_Dbg( p_vcd_access, message);
124 msg_Warn( p_vcd_access, message);
128 msg_Err( p_vcd_access, message);
131 msg_Warn( p_vcd_access, "%s\n%s %d", message,
132 _("The above message had unknown vcdimager log level"),
138 /*****************************************************************************
139 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
140 NULL is returned if something went wrong.
141 *****************************************************************************/
143 VCDReadBlock( access_t * p_access )
145 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
146 const int i_blocks = p_vcdplayer->i_blocks_per_read;
153 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
154 (long unsigned int) p_vcdplayer->i_lsn );
156 /* Allocate a block for the reading */
157 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
159 msg_Err( p_access, "cannot get a new block of size: %i",
160 i_blocks * M2F2_SECTOR_SIZE );
161 block_Release( p_block );
165 p_buf = (uint8_t *) p_block->p_buffer;
166 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
168 vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
170 p_access->info.i_pos += M2F2_SECTOR_SIZE;
172 switch ( read_status ) {
174 /* End reached. Return NULL to indicated this. */
175 /* We also set the postion to the end so the higher level
176 (demux?) doesn't try to keep reading. If everything works out
177 right this shouldn't have to happen.
180 if ( p_access->info.i_pos != p_access->info.i_size ) {
182 "At end but pos (%llu) is not size (%llu). Adjusting.",
183 p_access->info.i_pos, p_access->info.i_size );
184 p_access->info.i_pos = p_access->info.i_size;
189 block_Release( p_block );
193 memset(p_buf, 0, M2F2_SECTOR_SIZE);
196 printf("++++hacked\n");
202 /* Some sort of error. Should we increment lsn? to skip block?
204 block_Release( p_block );
206 case READ_STILL_FRAME:
208 /* FIXME The below should be done in an event thread.
212 msleep( MILLISECONDS_PER_SEC * *p_buf );
213 p_vcd->in_still = VLC_FALSE;
214 dbg_print(INPUT_DBG_STILL, "still wait time done");
216 vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);
220 block_Release( p_block );
223 memset(p_buf, 0, M2F2_SECTOR_SIZE);
236 p_buf += M2F2_SECTOR_SIZE;
237 /* Update seekpoint */
238 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
240 unsigned int i_entry = p_vcdplayer->play_item.num+1;
241 lsn_t i_lsn = vcdinfo_get_entry_lba(p_vcdplayer->vcd, i_entry);
242 if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LBA )
244 const track_t i_track = p_vcdplayer->i_track;
245 p_vcdplayer->play_item.num = i_entry;
246 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "entry change" );
247 VCDSetOrigin( p_access, i_lsn, i_track,
248 &(p_vcdplayer->play_item) );
257 /****************************************************************************
259 ****************************************************************************/
261 VCDSeek( access_t * p_access, int64_t i_pos )
263 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
266 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
267 const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
268 unsigned int i_entry = VCDINFO_INVALID_ENTRY;
271 /* Next sector to read */
272 p_access->info.i_pos = i_pos;
273 p_vcdplayer->i_lsn = (i_pos / (int64_t)M2F2_SECTOR_SIZE) +
274 p_vcdplayer->track_lsn;
276 switch (p_vcdplayer->play_item.type) {
277 case VCDINFO_ITEM_TYPE_TRACK:
278 case VCDINFO_ITEM_TYPE_ENTRY:
281 p_vcdplayer->b_valid_ep = VLC_FALSE;
285 if( p_vcdplayer->b_valid_ep )
287 for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
289 if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
291 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
292 "chapter", _("Entry"), "Setting entry" );
298 vcdinfo_itemid_t itemid;
299 itemid.num = i_entry;
300 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
301 VCDSetOrigin(p_access, p_vcdplayer->i_lsn, p_vcdplayer->i_track,
306 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
307 "orig %lu, cur: %lu, offset: %lld, entry %d",
308 (long unsigned int) p_vcdplayer->origin_lsn,
309 (long unsigned int) p_vcdplayer->i_lsn, i_pos,
313 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
315 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
316 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
319 /* Update current seekpoint */
320 if( i_seekpoint != p_access->info.i_seekpoint )
322 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
323 (long unsigned int) i_seekpoint );
324 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
325 p_access->info.i_seekpoint = i_seekpoint;
333 /*****************************************************************************
334 VCDEntryPoints: Reads the information about the entry points on the disc
335 and initializes area information with that.
336 Before calling this track information should have been read in.
337 *****************************************************************************/
339 VCDEntryPoints( access_t * p_access )
341 if (!p_access || !p_access->p_sys) return VLC_FALSE;
344 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
345 const unsigned int i_entries =
346 vcdinfo_get_num_entries(p_vcdplayer->vcd);
347 const track_t i_last_track
348 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
349 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
352 if (0 == i_entries) {
353 LOG_ERR ("no entires found -- something is wrong" );
357 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
359 if( p_vcdplayer->p_entries == NULL )
361 LOG_ERR ("not enough memory for entry points treatment" );
365 p_vcdplayer->i_entries = i_entries;
367 for( i = 0 ; i < i_entries ; i++ )
369 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
370 if( i_track <= i_last_track ) {
371 seekpoint_t *s = vlc_seekpoint_New();
374 snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
376 p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lba(p_vcdplayer->vcd, i);
378 s->psz_name = strdup(psz_entry);
380 (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lba(p_vcdplayer->vcd, i_track))
383 dbg_print( INPUT_DBG_MRL,
384 "%s, lsn %d, byte_offset %ld",
385 s->psz_name, p_vcdplayer->p_entries[i],
386 (unsigned long int) s->i_byte_offset);
387 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
388 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
391 msg_Warn( p_access, "wrong track number found in entry points" );
393 p_vcdplayer->b_valid_ep = VLC_TRUE;
398 /*****************************************************************************
399 * VCDSegments: Reads the information about the segments the disc.
400 *****************************************************************************/
402 VCDSegments( access_t * p_access )
404 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
408 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
410 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
411 "Segments: %d", p_vcdplayer->i_segments);
413 if ( 0 == p_vcdplayer->i_segments ) return VLC_FALSE;
415 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
416 p_vcdplayer->i_titles++;
418 t->i_size = 0; /* Not sure Segments have a size associated */
419 t->psz_name = strdup(_("Segments"));
421 /* We have one additional segment allocated so we can get the size
422 by subtracting seg[i+1] - seg[i].
424 p_vcdplayer->p_segments =
425 malloc( sizeof( lsn_t ) * (p_vcdplayer->i_segments+1) );
426 if( p_vcdplayer->p_segments == NULL )
428 LOG_ERR ("not enough memory for segment treatment" );
432 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
434 char psz_segment[100];
435 seekpoint_t *s = vlc_seekpoint_New();
436 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
438 snprintf( psz_segment, sizeof(psz_segment), "%s%02d", _("Segment "),
441 s->i_byte_offset = 0; /* Not sure what this would mean here */
442 s->psz_name = strdup(psz_segment);
443 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
446 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
447 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
448 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
449 p_vcdplayer->i_segments-1);
454 /*****************************************************************************
455 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
457 We start area addressing for tracks at 1 since the default area 0
458 is reserved for segments.
459 *****************************************************************************/
461 VCDTitles( access_t * p_access )
463 /* We'll assume a VCD has its first MPEG track
464 cdio_get_first_track_num()+1 could be used if one wanted to be
465 very careful about this. Note: cdio_get_first_track() will give the
466 ISO-9660 track before the MPEG tracks.
469 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
472 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
475 p_vcdplayer->i_titles = 0;
476 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
478 input_title_t *t = p_vcdplayer->p_title[i-1] =
479 vlc_input_title_New();
482 vcdinfo_get_track_sect_count( p_vcdplayer->vcd, i );
484 snprintf( psz_track, sizeof(psz_track), "%s%02d", _("Track "),
487 t->i_size = (i_secsize) * (int64_t) M2F2_SECTOR_SIZE;
488 t->psz_name = strdup(psz_track);
490 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld",
493 p_vcdplayer->i_titles++;
500 /*****************************************************************************
501 VCDLIDs: Reads the LIST IDs from the LOT.
502 *****************************************************************************/
504 VCDLIDs( access_t * p_access )
506 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
508 unsigned int i_lid, i_title;
510 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
511 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
513 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
514 "LIDs: %d", p_vcdplayer->i_lids);
516 if ( 0 == p_vcdplayer->i_lids ) return VLC_FALSE;
518 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
520 vcdinfo_visit_lot (p_vcdplayer->vcd, VLC_FALSE);
524 We need to change libvcdinfo to be more robust when there are
525 problems reading the extended PSD. Given that area-highlighting and
526 selection features in the extended PSD haven't been implemented,
527 it's best then to not try to read this at all.
529 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
530 vcdinfo_visit_lot (p_vcdplayer->vcd, VLC_TRUE);
534 /* Set up LIDs Navigation Menu */
535 t = vlc_input_title_New();
536 t->b_menu = VLC_TRUE;
537 t->psz_name = strdup( "LIDs" );
539 i_title = p_vcdplayer->i_tracks;
540 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
543 seekpoint_t *s = vlc_seekpoint_New();
545 snprintf( psz_lid, sizeof(psz_lid), "%s%02d", _("LID "),
548 s->i_byte_offset = 0; /* A lid doesn't have an offset
549 size associated with it */
550 s->psz_name = strdup(psz_lid);
551 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
555 #if DYNAMICALLY_ALLOCATED
556 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
558 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
559 p_vcdplayer->i_titles++;
565 /*****************************************************************************
566 * VCDParse: parse command line
567 *****************************************************************************/
569 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
570 /*out*/ vlc_bool_t *play_single_item )
572 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
577 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
578 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
580 *play_single_item = VLC_FALSE;
584 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
589 /* On Win32 we want the VCD access plugin to be explicitly requested,
590 * we end up with lots of problems otherwise */
591 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
594 if( !p_access->psz_path )
599 psz_parser = psz_source = strdup( p_access->psz_path );
601 /* Parse input string :
602 * [device][@[type][title]] */
603 while( *psz_parser && *psz_parser != '@' )
608 if( *psz_parser == '@' )
610 /* Found the divide between the source name and the
611 type+entry number. */
618 switch(*psz_parser) {
620 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
622 *play_single_item = VLC_TRUE;
625 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
627 *play_single_item = VLC_FALSE;
630 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
632 *play_single_item = VLC_TRUE;
635 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
637 *play_single_item = VLC_TRUE;
643 num = strtol( psz_parser, &psz_next, 10 );
644 if ( *psz_parser != '\0' && *psz_next == '\0')
650 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
656 /* No source specified, so figure it out. */
657 if( !p_access->psz_access ) return NULL;
659 psz_source = config_GetPsz( p_access, "vcd" );
661 if( !psz_source || 0==strlen(psz_source) ) {
662 /* Scan for a CD-ROM drive with a VCD in it. */
663 char **cd_drives = cdio_get_devices_with_cap( NULL,
664 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
665 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
667 if( NULL == cd_drives ) return NULL;
668 if( cd_drives[0] == NULL )
670 cdio_free_device_list( cd_drives );
673 psz_source = strdup( cd_drives[0] );
674 cdio_free_device_list( cd_drives );
678 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
679 "source=%s entry=%d type=%d",
680 psz_source, p_itemid->num, p_itemid->type);
686 Set's start origin subsequent seeks/reads
689 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
690 const vcdinfo_itemid_t *p_itemid )
692 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
694 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
695 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
698 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
700 p_access->info.i_pos = ( i_lsn - p_vcdplayer->track_lsn )
702 p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
703 | INPUT_UPDATE_SEEKPOINT;
706 switch (p_vcdplayer->play_item.type) {
707 case VCDINFO_ITEM_TYPE_ENTRY:
708 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
709 "chapter", _("Entry"), "Setting entry/segment");
710 p_access->info.i_title = i_track-1;
711 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
712 p_access->info.i_seekpoint = p_itemid->num;
715 case VCDINFO_ITEM_TYPE_SEGMENT:
716 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
717 "chapter", _("Segment"), "Setting entry/segment");
718 /* The last title entry is the for segments (when segments exist
719 and they must here. The segment seekpoints are stored after
720 the entry seekpoints and (zeroed) lid seekpoints.
722 p_access->info.i_title = p_vcdplayer->i_titles - 1;
723 p_access->info.i_size = 150 * M2F2_SECTOR_SIZE;
724 p_access->info.i_seekpoint = p_vcdplayer->i_entries
725 + p_vcdplayer->i_lids + p_itemid->num;
728 case VCDINFO_ITEM_TYPE_TRACK:
729 p_access->info.i_title = i_track-1;
730 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
731 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
735 msg_Warn( p_access, "can't set origin for play type %d",
736 p_vcdplayer->play_item.type );
740 VCDUpdateTitle( p_access );
744 /*****************************************************************************
745 * vcd_Open: Opens a VCD device or file initializes, a list of
746 tracks, segements and entry lsns and sizes and returns an opaque handle.
747 *****************************************************************************/
748 static vcdinfo_obj_t *
749 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
751 access_t *p_access = (access_t *)p_this;
752 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
753 vcdinfo_obj_t *p_vcdobj;
757 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
759 if( !psz_dev ) return NULL;
761 actual_dev=strdup(psz_dev);
762 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
770 Save summary info on tracks, segments and entries...
773 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
774 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
775 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
777 for (i=0; i<p_vcdplayer->i_tracks; i++) {
778 unsigned int track_num=i+1;
779 p_vcdplayer->track[i].size =
780 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
781 p_vcdplayer->track[i].start_LSN =
782 vcdinfo_get_track_lba(p_vcdobj, track_num);
785 p_vcdplayer->track = NULL;
787 if ( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
788 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
789 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
791 for (i=0; i<p_vcdplayer->i_entries; i++) {
792 p_vcdplayer->entry[i].size =
793 vcdinfo_get_entry_sect_count(p_vcdobj, i);
794 p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lba(p_vcdobj, i);
797 p_vcdplayer->entry = NULL;
799 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
800 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
801 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
803 for (i=0; i<p_vcdplayer->i_segments; i++) {
804 p_vcdplayer->segment[i].size =
805 vcdinfo_get_seg_sector_count(p_vcdobj, i);
806 p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
809 p_vcdplayer->segment = NULL;
815 /****************************************************************************
816 Update the "varname" variable to i_num without triggering a callback.
817 ****************************************************************************/
819 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
820 const char *p_varname, char *p_label,
821 const char *p_debug_label)
826 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
827 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
831 text.psz_string = p_label;
832 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
834 var_Change( p_access, p_varname, i_action, &val, NULL );
838 /*****************************************************************************
840 *****************************************************************************/
842 /*****************************************************************************
844 read in meta-information about VCD: the number of tracks, segments,
845 entries, size and starting information. Then set up state variables so
846 that we read/seek starting at the location specified.
848 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
849 and VLC_EGENERIC for some other error.
850 *****************************************************************************/
852 VCDOpen ( vlc_object_t *p_this )
854 access_t *p_access = (access_t *)p_this;
855 vcdplayer_t *p_vcdplayer;
857 vcdinfo_itemid_t itemid;
858 vlc_bool_t play_single_item = VLC_FALSE;
860 p_access->pf_read = NULL;
861 p_access->pf_block = VCDReadBlock;
862 p_access->pf_control = VCDControl;
863 p_access->pf_seek = VCDSeek;
865 p_access->info.i_update = 0;
866 p_access->info.i_size = 0;
867 p_access->info.i_pos = 0;
868 p_access->info.b_eof = VLC_FALSE;
869 p_access->info.i_title = 0;
870 p_access->info.i_seekpoint = 0;
872 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
874 if( p_vcdplayer == NULL )
876 LOG_ERR ("out of memory" );
880 p_access->p_sys = (access_sys_t *) p_vcdplayer;
882 /* Set where to log errors messages from libcdio. */
883 p_vcd_access = p_access;
884 cdio_log_set_handler ( cdio_log_handler );
885 vcd_log_set_handler ( vcd_log_handler );
887 psz_source = VCDParse( p_access, &itemid, &play_single_item );
889 if ( NULL == psz_source )
892 return( VLC_EGENERIC );
895 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
896 psz_source, p_access->psz_path );
898 p_vcdplayer->psz_source = strdup(psz_source);
899 p_vcdplayer->i_debug = config_GetInt( p_this,
900 MODULE_STRING "-debug" );
901 p_vcdplayer->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
902 "-blocks-per-read" );
903 p_vcdplayer->in_still = VLC_FALSE;
904 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
905 p_vcdplayer->p_input = vlc_object_find( p_access,
908 p_vcdplayer->p_demux = vlc_object_find( p_access,
911 p_vcdplayer->p_meta = vlc_meta_New();
912 p_vcdplayer->p_segments = NULL;
913 p_vcdplayer->p_entries = NULL;
917 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
919 msg_Warn( p_access, "could not open %s", psz_source );
923 p_vcdplayer->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcdplayer->vcd);;
925 /* Get track information. */
926 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
928 if( p_vcdplayer->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcdplayer->i_tracks ) {
929 vcdinfo_close( p_vcdplayer->vcd );
930 LOG_ERR ("no movie tracks found" );
934 /* Build Navigation Title table for the tracks. */
935 VCDTitles( p_access );
937 /* Add into the above entry points as "Chapters". */
938 if( ! VCDEntryPoints( p_access ) )
940 msg_Warn( p_access, "could not read entry points, will not use them" );
941 p_vcdplayer->b_valid_ep = VLC_FALSE;
944 /* Initialize LID info and add that as a menu item */
945 if( ! VCDLIDs( p_access ) )
947 msg_Warn( p_access, "could not read entry LIDs" );
950 /* Do we set PBC (via LID) on? */
952 ( VCDINFO_ITEM_TYPE_LID == itemid.type
953 && p_vcdplayer->i_lids > itemid.num )
955 : VCDINFO_INVALID_ENTRY;
957 /* Initialize segment information and add that a "Track". */
958 VCDSegments( p_access );
960 vcdplayer_play( p_access, itemid );
962 p_access->psz_demux = strdup( "ps" );
965 if (play_single_item)
966 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
970 p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
971 p_vcdplayer->p_intf->b_block = VLC_FALSE;
972 p_vcdplayer->p_access = p_access;
975 intf_RunThread( p_vcdplayer->p_intf );
987 /*****************************************************************************
988 * VCDClose: closes VCD releasing allocated memory.
989 *****************************************************************************/
991 VCDClose ( vlc_object_t *p_this )
993 access_t *p_access = (access_t *)p_this;
994 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
996 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
998 vcdinfo_close( p_vcdplayer->vcd );
1000 FREE_AND_NULL( p_vcdplayer->p_entries );
1001 FREE_AND_NULL( p_vcdplayer->p_segments );
1002 FREE_AND_NULL( p_vcdplayer->psz_source );
1003 FREE_AND_NULL( p_vcdplayer->track );
1004 FREE_AND_NULL( p_vcdplayer->segment );
1005 FREE_AND_NULL( p_vcdplayer->entry );
1007 free( p_vcdplayer );
1008 p_access->p_sys = NULL;
1009 p_vcd_access = NULL;
1012 /*****************************************************************************
1013 * Control: The front-end or vlc engine calls here to ether get
1014 * information such as meta information or plugin capabilities or to
1015 * issue miscellaneous "set" requests.
1016 *****************************************************************************/
1017 static int VCDControl( access_t *p_access, int i_query, va_list args )
1019 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1023 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1024 "query %d", i_query );
1028 /* Pass back a copy of meta information that was gathered when we
1029 during the Open/Initialize call.
1031 case ACCESS_GET_META:
1033 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1035 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1037 if ( p_vcdplayer->p_meta ) {
1038 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1039 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1041 msg_Warn( p_access, "tried to copy NULL meta info" );
1045 return VLC_EGENERIC;
1047 case ACCESS_CAN_SEEK:
1048 case ACCESS_CAN_FASTSEEK:
1049 case ACCESS_CAN_PAUSE:
1050 case ACCESS_CAN_CONTROL_PACE:
1052 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1054 dbg_print( INPUT_DBG_EVENT,
1055 "seek/fastseek/pause/can_control_pace" );
1056 *pb_bool = VLC_TRUE;
1062 case ACCESS_GET_MTU:
1063 pi_int = (int*)va_arg( args, int * );
1064 *pi_int = (p_vcdplayer->i_blocks_per_read * M2F2_SECTOR_SIZE);
1065 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1068 case ACCESS_GET_PTS_DELAY:
1070 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1071 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1072 * MILLISECONDS_PER_SEC;
1073 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1079 case ACCESS_SET_PAUSE_STATE:
1080 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1084 case ACCESS_GET_TITLE_INFO:
1086 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1087 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1088 input_title_t ***ppp_title
1089 = (input_title_t***)va_arg( args, input_title_t*** );
1090 char *psz_mrl = malloc( psz_mrl_max );
1093 pi_int = (int*)va_arg( args, int* );
1095 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1096 p_vcdplayer->i_titles );
1098 if( psz_mrl == NULL ) {
1099 msg_Warn( p_access, "out of memory" );
1101 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1102 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1103 VCDMetaInfo( p_access, psz_mrl );
1107 /* Duplicate title info */
1108 if( p_vcdplayer->i_titles == 0 )
1110 *pi_int = 0; ppp_title = NULL;
1113 *pi_int = p_vcdplayer->i_titles;
1114 *ppp_title = malloc( sizeof( input_title_t **)
1115 * p_vcdplayer->i_titles );
1117 if (!*ppp_title) return VLC_ENOMEM;
1119 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1121 if ( p_vcdplayer->p_title[i] )
1123 vlc_input_title_Duplicate( p_vcdplayer->p_title[i] );
1128 case ACCESS_SET_TITLE:
1129 i = (int)va_arg( args, int );
1131 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1132 if( i != p_access->info.i_title )
1134 vcdinfo_itemid_t itemid;
1135 track_t i_track = i+1;
1136 unsigned int i_entry =
1137 vcdinfo_track_get_entry( p_vcdplayer->vcd, i_track);
1139 /* FIXME! For now we are assuming titles are only
1140 tracks and that track == title+1 */
1141 itemid.num = i_track;
1142 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1144 VCDSetOrigin(p_access,
1145 vcdinfo_get_entry_lba(p_vcdplayer->vcd, i_entry),
1150 case ACCESS_SET_SEEKPOINT:
1152 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1153 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1155 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1156 if( t->i_seekpoint > 0 )
1158 track_t i_track = p_access->info.i_title+1;
1161 /* FIXME! For now we are assuming titles are only
1162 tracks and that track == title+1 and we the play
1163 item is entries (not tracks or lids).
1164 We need to generalize all of this.
1167 if (i < p_vcdplayer->i_entries)
1169 p_vcdplayer->play_item.num = i;
1170 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1171 lsn = vcdinfo_get_entry_lba(p_vcdplayer->vcd, i);
1172 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1174 p_vcdplayer->play_item.num = i
1175 = i - p_vcdplayer->i_entries;
1176 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1180 p_vcdplayer->play_item.num = i
1181 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1182 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1183 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1186 VCDSetOrigin( p_access,
1187 vcdinfo_get_entry_lba(p_vcdplayer->vcd, i),
1188 i_track, &(p_vcdplayer->play_item) );
1193 case ACCESS_SET_PRIVATE_ID_STATE:
1194 dbg_print( INPUT_DBG_EVENT, "set private id" );
1195 return VLC_EGENERIC;
1198 msg_Warn( p_access, "unimplemented query in control" );
1199 return VLC_EGENERIC;