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_lsn(p_vcdplayer->vcd, i_entry);
242 if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
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_lsn(p_vcdplayer->vcd, i);
378 s->psz_name = strdup(psz_entry);
380 (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(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 );
554 #if DYNAMICALLY_ALLOCATED
555 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
557 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
558 p_vcdplayer->i_titles++;
564 /*****************************************************************************
565 * VCDParse: parse command line
566 *****************************************************************************/
568 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
569 /*out*/ vlc_bool_t *play_single_item )
571 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
576 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
577 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
579 *play_single_item = VLC_FALSE;
583 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
588 /* On Win32 we want the VCD access plugin to be explicitly requested,
589 * we end up with lots of problems otherwise */
590 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
593 if( !p_access->psz_path )
598 psz_parser = psz_source = strdup( p_access->psz_path );
600 /* Parse input string :
601 * [device][@[type][title]] */
602 while( *psz_parser && *psz_parser != '@' )
607 if( *psz_parser == '@' )
609 /* Found the divide between the source name and the
610 type+entry number. */
617 switch(*psz_parser) {
619 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
621 *play_single_item = VLC_TRUE;
624 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
626 *play_single_item = VLC_FALSE;
629 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
631 *play_single_item = VLC_TRUE;
634 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
636 *play_single_item = VLC_TRUE;
642 num = strtol( psz_parser, &psz_next, 10 );
643 if ( *psz_parser != '\0' && *psz_next == '\0')
649 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
655 /* No source specified, so figure it out. */
656 if( !p_access->psz_access ) return NULL;
658 psz_source = config_GetPsz( p_access, "vcd" );
660 if( !psz_source || 0==strlen(psz_source) ) {
661 /* Scan for a CD-ROM drive with a VCD in it. */
662 char **cd_drives = cdio_get_devices_with_cap( NULL,
663 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
664 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
666 if( NULL == cd_drives ) return NULL;
667 if( cd_drives[0] == NULL )
669 cdio_free_device_list( cd_drives );
672 psz_source = strdup( cd_drives[0] );
673 cdio_free_device_list( cd_drives );
677 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
678 "source=%s entry=%d type=%d",
679 psz_source, p_itemid->num, p_itemid->type);
685 Set's start origin subsequent seeks/reads
688 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
689 const vcdinfo_itemid_t *p_itemid )
691 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
693 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
694 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
697 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
699 p_access->info.i_pos = ( i_lsn - p_vcdplayer->track_lsn )
701 p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
702 | INPUT_UPDATE_SEEKPOINT;
705 switch (p_vcdplayer->play_item.type) {
706 case VCDINFO_ITEM_TYPE_ENTRY:
707 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
708 "chapter", _("Entry"), "Setting entry/segment");
709 p_access->info.i_title = i_track-1;
710 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
711 p_access->info.i_seekpoint = p_itemid->num;
714 case VCDINFO_ITEM_TYPE_SEGMENT:
715 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
716 "chapter", _("Segment"), "Setting entry/segment");
717 /* The last title entry is the for segments (when segments exist
718 and they must here. The segment seekpoints are stored after
719 the entry seekpoints and (zeroed) lid seekpoints.
721 p_access->info.i_title = p_vcdplayer->i_titles - 1;
722 p_access->info.i_size = 150 * M2F2_SECTOR_SIZE;
723 p_access->info.i_seekpoint = p_vcdplayer->i_entries
724 + p_vcdplayer->i_lids + p_itemid->num;
727 case VCDINFO_ITEM_TYPE_TRACK:
728 p_access->info.i_title = i_track-1;
729 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
730 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
734 msg_Warn( p_access, "can't set origin for play type %d",
735 p_vcdplayer->play_item.type );
739 VCDUpdateTitle( p_access );
743 /*****************************************************************************
744 * vcd_Open: Opens a VCD device or file initializes, a list of
745 tracks, segements and entry lsns and sizes and returns an opaque handle.
746 *****************************************************************************/
747 static vcdinfo_obj_t *
748 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
750 access_t *p_access = (access_t *)p_this;
751 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
752 vcdinfo_obj_t *p_vcdobj;
756 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
758 if( !psz_dev ) return NULL;
760 actual_dev=strdup(psz_dev);
761 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
769 Save summary info on tracks, segments and entries...
772 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
773 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
774 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
776 for (i=0; i<p_vcdplayer->i_tracks; i++) {
777 unsigned int track_num=i+1;
778 p_vcdplayer->track[i].size =
779 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
780 p_vcdplayer->track[i].start_LSN =
781 vcdinfo_get_track_lsn(p_vcdobj, track_num);
784 p_vcdplayer->track = NULL;
786 if ( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
787 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
788 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
790 for (i=0; i<p_vcdplayer->i_entries; i++) {
791 p_vcdplayer->entry[i].size =
792 vcdinfo_get_entry_sect_count(p_vcdobj, i);
793 p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lsn(p_vcdobj, i);
796 p_vcdplayer->entry = NULL;
798 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
799 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
800 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
802 for (i=0; i<p_vcdplayer->i_segments; i++) {
803 p_vcdplayer->segment[i].size =
804 vcdinfo_get_seg_sector_count(p_vcdobj, i);
805 p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
808 p_vcdplayer->segment = NULL;
813 /****************************************************************************
814 Update the "varname" variable to i_num without triggering a callback.
815 ****************************************************************************/
817 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
818 const char *p_varname, char *p_label,
819 const char *p_debug_label)
824 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
825 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
829 text.psz_string = p_label;
830 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
832 var_Change( p_access, p_varname, i_action, &val, NULL );
836 /*****************************************************************************
838 *****************************************************************************/
840 /*****************************************************************************
842 read in meta-information about VCD: the number of tracks, segments,
843 entries, size and starting information. Then set up state variables so
844 that we read/seek starting at the location specified.
846 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
847 and VLC_EGENERIC for some other error.
848 *****************************************************************************/
850 VCDOpen ( vlc_object_t *p_this )
852 access_t *p_access = (access_t *)p_this;
853 vcdplayer_t *p_vcdplayer;
855 vcdinfo_itemid_t itemid;
856 vlc_bool_t play_single_item = VLC_FALSE;
858 p_access->pf_read = NULL;
859 p_access->pf_block = VCDReadBlock;
860 p_access->pf_control = VCDControl;
861 p_access->pf_seek = VCDSeek;
863 p_access->info.i_update = 0;
864 p_access->info.i_size = 0;
865 p_access->info.i_pos = 0;
866 p_access->info.b_eof = VLC_FALSE;
867 p_access->info.i_title = 0;
868 p_access->info.i_seekpoint = 0;
870 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
872 if( p_vcdplayer == NULL )
874 LOG_ERR ("out of memory" );
878 p_access->p_sys = (access_sys_t *) p_vcdplayer;
880 /* Set where to log errors messages from libcdio. */
881 p_vcd_access = p_access;
882 cdio_log_set_handler ( cdio_log_handler );
883 vcd_log_set_handler ( vcd_log_handler );
885 psz_source = VCDParse( p_access, &itemid, &play_single_item );
887 if ( NULL == psz_source )
890 return( VLC_EGENERIC );
893 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
894 psz_source, p_access->psz_path );
896 p_vcdplayer->psz_source = strdup(psz_source);
897 p_vcdplayer->i_debug = config_GetInt( p_this,
898 MODULE_STRING "-debug" );
899 p_vcdplayer->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
900 "-blocks-per-read" );
901 p_vcdplayer->in_still = VLC_FALSE;
902 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
903 p_vcdplayer->p_input = vlc_object_find( p_access,
906 p_vcdplayer->p_demux = vlc_object_find( p_access,
909 p_vcdplayer->p_meta = vlc_meta_New();
910 p_vcdplayer->p_segments = NULL;
911 p_vcdplayer->p_entries = NULL;
915 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
917 msg_Warn( p_access, "could not open %s", psz_source );
921 p_vcdplayer->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcdplayer->vcd);;
923 /* Get track information. */
924 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
926 if( p_vcdplayer->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcdplayer->i_tracks ) {
927 vcdinfo_close( p_vcdplayer->vcd );
928 LOG_ERR ("no movie tracks found" );
932 /* Build Navigation Title table for the tracks. */
933 VCDTitles( p_access );
935 /* Add into the above entry points as "Chapters". */
936 if( ! VCDEntryPoints( p_access ) )
938 msg_Warn( p_access, "could not read entry points, will not use them" );
939 p_vcdplayer->b_valid_ep = VLC_FALSE;
942 /* Initialize LID info and add that as a menu item */
943 if( ! VCDLIDs( p_access ) )
945 msg_Warn( p_access, "could not read entry LIDs" );
948 /* Do we set PBC (via LID) on? */
950 ( VCDINFO_ITEM_TYPE_LID == itemid.type
951 && p_vcdplayer->i_lids > itemid.num )
953 : VCDINFO_INVALID_ENTRY;
955 /* Initialize segment information and add that a "Track". */
956 VCDSegments( p_access );
958 vcdplayer_play( p_access, itemid );
960 p_access->psz_demux = strdup( "ps" );
963 if (play_single_item)
964 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
968 p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
969 p_vcdplayer->p_intf->b_block = VLC_FALSE;
970 p_vcdplayer->p_access = p_access;
973 intf_RunThread( p_vcdplayer->p_intf );
980 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
981 if( p_vcdplayer->p_demux ) vlc_object_release( p_vcdplayer->p_demux );
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 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
1001 if( p_vcdplayer->p_demux ) vlc_object_release( p_vcdplayer->p_demux );
1004 FREE_AND_NULL( p_vcdplayer->p_entries );
1005 FREE_AND_NULL( p_vcdplayer->p_segments );
1006 FREE_AND_NULL( p_vcdplayer->psz_source );
1007 FREE_AND_NULL( p_vcdplayer->track );
1008 FREE_AND_NULL( p_vcdplayer->segment );
1009 FREE_AND_NULL( p_vcdplayer->entry );
1011 free( p_vcdplayer );
1012 p_access->p_sys = NULL;
1013 p_vcd_access = NULL;
1016 /*****************************************************************************
1017 * Control: The front-end or vlc engine calls here to ether get
1018 * information such as meta information or plugin capabilities or to
1019 * issue miscellaneous "set" requests.
1020 *****************************************************************************/
1021 static int VCDControl( access_t *p_access, int i_query, va_list args )
1023 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1027 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1028 "query %d", i_query );
1032 /* Pass back a copy of meta information that was gathered when we
1033 during the Open/Initialize call.
1035 case ACCESS_GET_META:
1037 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1039 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1041 if ( p_vcdplayer->p_meta ) {
1042 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1043 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1045 msg_Warn( p_access, "tried to copy NULL meta info" );
1049 return VLC_EGENERIC;
1051 case ACCESS_CAN_SEEK:
1052 case ACCESS_CAN_FASTSEEK:
1053 case ACCESS_CAN_PAUSE:
1054 case ACCESS_CAN_CONTROL_PACE:
1056 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1058 dbg_print( INPUT_DBG_EVENT,
1059 "seek/fastseek/pause/can_control_pace" );
1060 *pb_bool = VLC_TRUE;
1066 case ACCESS_GET_MTU:
1067 pi_int = (int*)va_arg( args, int * );
1068 *pi_int = (p_vcdplayer->i_blocks_per_read * M2F2_SECTOR_SIZE);
1069 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1072 case ACCESS_GET_PTS_DELAY:
1074 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1075 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1076 * MILLISECONDS_PER_SEC;
1077 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1083 case ACCESS_SET_PAUSE_STATE:
1084 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1088 case ACCESS_GET_TITLE_INFO:
1090 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1091 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1092 input_title_t ***ppp_title
1093 = (input_title_t***)va_arg( args, input_title_t*** );
1094 char *psz_mrl = malloc( psz_mrl_max );
1097 pi_int = (int*)va_arg( args, int* );
1099 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1100 p_vcdplayer->i_titles );
1102 if( psz_mrl == NULL ) {
1103 msg_Warn( p_access, "out of memory" );
1105 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1106 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1107 VCDMetaInfo( p_access, psz_mrl );
1111 /* Duplicate title info */
1112 if( p_vcdplayer->i_titles == 0 )
1114 *pi_int = 0; ppp_title = NULL;
1117 *pi_int = p_vcdplayer->i_titles;
1118 *ppp_title = malloc( sizeof( input_title_t **)
1119 * p_vcdplayer->i_titles );
1121 if (!*ppp_title) return VLC_ENOMEM;
1123 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1125 if ( p_vcdplayer->p_title[i] )
1127 vlc_input_title_Duplicate( p_vcdplayer->p_title[i] );
1132 case ACCESS_SET_TITLE:
1133 i = (int)va_arg( args, int );
1135 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1136 if( i != p_access->info.i_title )
1138 vcdinfo_itemid_t itemid;
1139 track_t i_track = i+1;
1140 unsigned int i_entry =
1141 vcdinfo_track_get_entry( p_vcdplayer->vcd, i_track);
1143 /* FIXME! For now we are assuming titles are only
1144 tracks and that track == title+1 */
1145 itemid.num = i_track;
1146 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1148 VCDSetOrigin(p_access,
1149 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry),
1154 case ACCESS_SET_SEEKPOINT:
1156 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1157 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1159 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1160 if( t->i_seekpoint > 0 )
1162 track_t i_track = p_access->info.i_title+1;
1165 /* FIXME! For now we are assuming titles are only
1166 tracks and that track == title+1 and we the play
1167 item is entries (not tracks or lids).
1168 We need to generalize all of this.
1171 if (i < p_vcdplayer->i_entries)
1173 p_vcdplayer->play_item.num = i;
1174 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1175 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1176 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1178 p_vcdplayer->play_item.num = i
1179 = i - p_vcdplayer->i_entries;
1180 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1184 p_vcdplayer->play_item.num = i
1185 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1186 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1187 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1190 VCDSetOrigin( p_access,
1191 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i),
1192 i_track, &(p_vcdplayer->play_item) );
1197 case ACCESS_SET_PRIVATE_ID_STATE:
1198 dbg_print( INPUT_DBG_EVENT, "set private id" );
1199 return VLC_EGENERIC;
1202 msg_Warn( p_access, "unimplemented query in control" );
1203 return VLC_EGENERIC;