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, 2005 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
37 #include <vlc_interface.h>
38 #include <vlc_input.h>
39 #include <vlc_access.h>
42 #include <cdio/cdio.h>
43 #include <cdio/cd_types.h>
44 #include <cdio/logging.h>
45 #include <cdio/util.h>
46 #include <libvcd/info.h>
47 #include <libvcd/logging.h>
52 extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
53 const vcdinfo_itemid_t *p_itemid );
55 /*****************************************************************************
57 *****************************************************************************/
59 /* First those which are accessed from outside (via pointers). */
60 static block_t *VCDReadBlock ( access_t * );
62 static int VCDControl ( access_t *p_access, int i_query,
65 /* Now those which are strictly internal */
66 static bool VCDEntryPoints ( access_t * );
67 static bool VCDLIDs ( access_t * );
68 static bool VCDSegments ( access_t * );
69 static int VCDTitles ( access_t * );
70 static char *VCDParse ( access_t *,
71 /*out*/ vcdinfo_itemid_t * p_itemid ,
72 /*out*/ bool *play_single_item );
74 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
75 const char *p_varname, char *p_label,
76 const char *p_debug_label );
78 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
80 /****************************************************************************
82 ****************************************************************************/
84 /* FIXME: This variable is a hack. Would be nice to eliminate the
87 static access_t *p_vcd_access = NULL;
89 /* process messages that originate from libcdio. */
91 cdio_log_handler (cdio_log_level_t level, const char message[])
93 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
97 if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
98 msg_Dbg( p_vcd_access, "%s", message);
101 msg_Warn( p_vcd_access, "%s", message);
104 case CDIO_LOG_ASSERT:
105 msg_Err( p_vcd_access, "%s", message);
108 msg_Warn( p_vcd_access, "%s\n%s %d", message,
109 _("The above message had unknown log level"),
115 /* process messages that originate from vcdinfo. */
117 vcd_log_handler (vcd_log_level_t level, const char message[])
119 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
123 if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
124 msg_Dbg( p_vcd_access, "%s", message);
127 msg_Warn( p_vcd_access, "%s", message);
131 msg_Err( p_vcd_access, "%s", message);
134 msg_Warn( p_vcd_access, "%s\n%s %d", message,
135 _("The above message had unknown vcdimager log level"),
141 /*****************************************************************************
142 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
143 NULL is returned if something went wrong.
144 *****************************************************************************/
146 VCDReadBlock( access_t * p_access )
148 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
149 const int i_blocks = p_vcdplayer->i_blocks_per_read;
156 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
157 (long unsigned int) p_vcdplayer->i_lsn );
159 /* Allocate a block for the reading */
160 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
162 msg_Err( p_access, "cannot get a new block of size: %i",
163 i_blocks * M2F2_SECTOR_SIZE );
164 block_Release( p_block );
168 p_buf = (uint8_t *) p_block->p_buffer;
169 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
171 vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
173 p_access->info.i_pos += M2F2_SECTOR_SIZE;
175 switch ( read_status ) {
177 /* End reached. Return NULL to indicated this. */
178 /* We also set the postion to the end so the higher level
179 (demux?) doesn't try to keep reading. If everything works out
180 right this shouldn't have to happen.
183 if ( p_access->info.i_pos != p_access->info.i_size ) {
185 "At end but pos (%llu) is not size (%llu). Adjusting.",
186 p_access->info.i_pos, p_access->info.i_size );
187 p_access->info.i_pos = p_access->info.i_size;
191 block_Release( p_block );
195 /* Some sort of error. Should we increment lsn? to skip block?
197 block_Release( p_block );
199 case READ_STILL_FRAME:
201 /* FIXME The below should be done in an event thread.
205 msleep( MILLISECONDS_PER_SEC * *p_buf );
206 VCDSetOrigin(p_access, p_vcdplayer->origin_lsn, p_vcdplayer->i_track,
207 &(p_vcdplayer->play_item));
208 // p_vcd->in_still = false;
209 dbg_print(INPUT_DBG_STILL, "still wait time done");
211 vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);
214 block_Release( p_block );
224 p_buf += M2F2_SECTOR_SIZE;
225 /* Update seekpoint */
226 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
228 unsigned int i_entry = p_vcdplayer->play_item.num+1;
229 lsn_t i_lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
230 if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
232 const track_t i_track = p_vcdplayer->i_track;
234 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
235 "entry change to %d, current LSN %u >= end %u",
236 i_entry, p_vcdplayer->i_lsn, i_lsn);
238 p_vcdplayer->play_item.num = i_entry;
240 VCDSetOrigin( p_access, i_lsn, i_track,
241 &(p_vcdplayer->play_item) );
250 /****************************************************************************
252 ****************************************************************************/
254 VCDSeek( access_t * p_access, int64_t i_pos )
256 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
259 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
260 const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
261 unsigned int i_entry = VCDINFO_INVALID_ENTRY;
264 /* Next sector to read */
265 p_access->info.i_pos = i_pos;
266 p_vcdplayer->i_lsn = (i_pos / (int64_t) M2F2_SECTOR_SIZE) +
267 p_vcdplayer->origin_lsn;
269 switch (p_vcdplayer->play_item.type) {
270 case VCDINFO_ITEM_TYPE_TRACK:
271 case VCDINFO_ITEM_TYPE_ENTRY:
274 p_vcdplayer->b_valid_ep = false;
278 if( p_vcdplayer->b_valid_ep )
280 for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
282 if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
284 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
285 "chapter", _("Entry"), "Setting entry" );
291 vcdinfo_itemid_t itemid;
292 itemid.num = i_entry;
293 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
294 VCDSetOrigin(p_access, p_vcdplayer->i_lsn, p_vcdplayer->i_track,
299 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
300 "orig %lu, cur: %lu, offset: %lld, entry %d",
301 (long unsigned int) p_vcdplayer->origin_lsn,
302 (long unsigned int) p_vcdplayer->i_lsn, i_pos,
306 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
308 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
309 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
312 /* Update current seekpoint */
313 if( i_seekpoint != p_access->info.i_seekpoint )
315 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
316 (long unsigned int) i_seekpoint );
317 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
318 p_access->info.i_seekpoint = i_seekpoint;
322 p_access->info.b_eof = false;
327 /*****************************************************************************
328 VCDEntryPoints: Reads the information about the entry points on the disc
329 and initializes area information with that.
330 Before calling this track information should have been read in.
331 *****************************************************************************/
333 VCDEntryPoints( access_t * p_access )
335 if (!p_access || !p_access->p_sys) return false;
338 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
339 const unsigned int i_entries =
340 vcdinfo_get_num_entries(p_vcdplayer->vcd);
341 const track_t i_last_track
342 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
343 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
346 if (0 == i_entries) {
347 LOG_ERR ("no entires found -- something is wrong" );
351 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
353 if( p_vcdplayer->p_entries == NULL )
355 LOG_ERR ("not enough memory for entry points treatment" );
359 p_vcdplayer->i_entries = i_entries;
361 for( i = 0 ; i < i_entries ; i++ )
363 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
364 if( i_track <= i_last_track ) {
365 seekpoint_t *s = vlc_seekpoint_New();
368 snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i );
370 p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
372 s->psz_name = strdup(psz_entry);
374 (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track))
377 dbg_print( INPUT_DBG_MRL,
378 "%s, lsn %d, byte_offset %ld",
379 s->psz_name, p_vcdplayer->p_entries[i],
380 (unsigned long int) s->i_byte_offset);
381 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
382 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
385 msg_Warn( p_access, "wrong track number found in entry points" );
387 p_vcdplayer->b_valid_ep = true;
392 /*****************************************************************************
393 * VCDSegments: Reads the information about the segments the disc.
394 *****************************************************************************/
396 VCDSegments( access_t * p_access )
398 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
402 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
404 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
405 "Segments: %d", p_vcdplayer->i_segments);
407 if ( 0 == p_vcdplayer->i_segments ) return false;
409 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
410 p_vcdplayer->i_titles++;
412 t->i_size = 0; /* Not sure Segments have a size associated */
413 t->psz_name = strdup(_("Segments"));
415 /* We have one additional segment allocated so we can get the size
416 by subtracting seg[i+1] - seg[i].
418 p_vcdplayer->p_segments =
419 malloc( sizeof( lsn_t ) * (p_vcdplayer->i_segments+1) );
420 if( p_vcdplayer->p_segments == NULL )
422 LOG_ERR ("not enough memory for segment treatment" );
426 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
428 char psz_segment[100];
429 seekpoint_t *s = vlc_seekpoint_New();
430 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
432 snprintf( psz_segment, sizeof(psz_segment), "%s %02d", _("Segment"),
435 s->i_byte_offset = 0; /* Not sure what this would mean here */
436 s->psz_name = strdup(psz_segment);
437 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
440 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
441 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
442 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
443 p_vcdplayer->i_segments-1);
448 /*****************************************************************************
449 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
451 We start area addressing for tracks at 1 since the default area 0
452 is reserved for segments.
453 *****************************************************************************/
455 VCDTitles( access_t * p_access )
457 /* We'll assume a VCD has its first MPEG track
458 cdio_get_first_track_num()+1 could be used if one wanted to be
459 very careful about this. Note: cdio_get_first_track() will give the
460 ISO-9660 track before the MPEG tracks.
463 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
466 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
469 p_vcdplayer->i_titles = 0;
470 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
472 input_title_t *t = p_vcdplayer->p_title[i-1] =
473 vlc_input_title_New();
476 snprintf( psz_track, sizeof(psz_track), "%s %02d", _("Track"),
478 t->i_size = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
480 * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
481 t->psz_name = strdup(psz_track);
483 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld", i, t->i_size );
485 p_vcdplayer->i_titles++;
492 /*****************************************************************************
493 VCDLIDs: Reads the LIST IDs from the LOT.
494 *****************************************************************************/
496 VCDLIDs( access_t * p_access )
498 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
500 unsigned int i_lid, i_title;
502 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
503 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
505 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
506 "LIDs: %d", p_vcdplayer->i_lids);
508 if ( 0 == p_vcdplayer->i_lids ) return false;
510 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
512 vcdinfo_visit_lot (p_vcdplayer->vcd, false);
516 We need to change libvcdinfo to be more robust when there are
517 problems reading the extended PSD. Given that area-highlighting and
518 selection features in the extended PSD haven't been implemented,
519 it's best then to not try to read this at all.
521 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
522 vcdinfo_visit_lot (p_vcdplayer->vcd, true);
526 /* Set up LIDs Navigation Menu */
527 t = vlc_input_title_New();
529 t->psz_name = strdup( "LIDs" );
531 i_title = p_vcdplayer->i_tracks;
532 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
535 seekpoint_t *s = vlc_seekpoint_New();
537 snprintf( psz_lid, sizeof(psz_lid), "%s %02d", _("LID"),
540 s->i_byte_offset = 0; /* A lid doesn't have an offset
541 size associated with it */
542 s->psz_name = strdup(psz_lid);
543 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
546 #if DYNAMICALLY_ALLOCATED
547 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
549 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
550 p_vcdplayer->i_titles++;
556 /*****************************************************************************
557 * VCDParse: parse command line
558 *****************************************************************************/
560 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
561 /*out*/ bool *play_single_item )
563 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
568 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
569 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
571 *play_single_item = false;
575 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
580 /* On Win32 we want the VCD access plugin to be explicitly requested,
581 * we end up with lots of problems otherwise */
582 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
585 if( !p_access->psz_path )
590 psz_parser = psz_source = strdup( p_access->psz_path );
592 /* Parse input string :
593 * [device][@[type][title]] */
594 while( *psz_parser && *psz_parser != '@' )
599 if( *psz_parser == '@' )
601 /* Found the divide between the source name and the
602 type+entry number. */
609 switch(*psz_parser) {
611 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
613 *play_single_item = true;
616 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
618 *play_single_item = false;
621 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
623 *play_single_item = true;
626 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
628 *play_single_item = true;
634 num = strtol( psz_parser, &psz_next, 10 );
635 if ( *psz_parser != '\0' && *psz_next == '\0')
641 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
647 /* No source specified, so figure it out. */
648 if( !p_access->psz_access ) return NULL;
650 psz_source = config_GetPsz( p_access, "vcd" );
652 if( !psz_source || 0==strlen(psz_source) ) {
653 /* Scan for a CD-ROM drive with a VCD in it. */
654 char **cd_drives = cdio_get_devices_with_cap( NULL,
655 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
656 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
658 if( NULL == cd_drives ) return NULL;
659 if( cd_drives[0] == NULL )
661 cdio_free_device_list( cd_drives );
664 psz_source = strdup( cd_drives[0] );
665 cdio_free_device_list( cd_drives );
669 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
670 "source=%s entry=%d type=%d",
671 psz_source, p_itemid->num, p_itemid->type);
677 Sets start origin for subsequent seeks/reads
680 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
681 const vcdinfo_itemid_t *p_itemid )
683 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
685 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
686 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
689 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
691 switch (p_vcdplayer->play_item.type) {
692 case VCDINFO_ITEM_TYPE_ENTRY:
693 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
694 "chapter", _("Entry"), "Setting entry/segment");
695 p_access->info.i_title = i_track-1;
696 if (p_vcdplayer->b_track_length)
698 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
699 p_access->info.i_pos = (int64_t) M2F2_SECTOR_SIZE *
700 (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track) - i_lsn) ;
702 p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
703 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd, p_itemid->num);
704 p_access->info.i_pos = 0;
706 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %llu, pos: %llu",
707 p_access->info.i_size, p_access->info.i_pos );
708 p_access->info.i_seekpoint = p_itemid->num;
711 case VCDINFO_ITEM_TYPE_SEGMENT:
712 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
713 "chapter", _("Segment"), "Setting entry/segment");
714 /* The last title entry is the for segments (when segments exist
715 and they must here. The segment seekpoints are stored after
716 the entry seekpoints and (zeroed) lid seekpoints.
718 p_access->info.i_title = p_vcdplayer->i_titles - 1;
719 p_access->info.i_size = 0; /* No seeking on stills, please. */
720 p_access->info.i_pos = 0;
721 p_access->info.i_seekpoint = p_vcdplayer->i_entries
722 + p_vcdplayer->i_lids + p_itemid->num;
725 case VCDINFO_ITEM_TYPE_TRACK:
726 p_access->info.i_title = i_track-1;
727 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
728 p_access->info.i_pos = 0;
729 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 );
738 p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
739 | INPUT_UPDATE_SEEKPOINT;
741 VCDUpdateTitle( p_access );
745 /*****************************************************************************
746 * vcd_Open: Opens a VCD device or file initializes, a list of
747 tracks, segements and entry lsns and sizes and returns an opaque handle.
748 *****************************************************************************/
749 static vcdinfo_obj_t *
750 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
752 access_t *p_access = (access_t *)p_this;
753 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
754 vcdinfo_obj_t *p_vcdobj;
758 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
760 if( !psz_dev ) return NULL;
762 actual_dev=strdup(psz_dev);
763 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
771 Save summary info on tracks, segments and entries...
774 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
775 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
776 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
778 for (i=0; i<p_vcdplayer->i_tracks; i++) {
779 unsigned int track_num=i+1;
780 p_vcdplayer->track[i].size =
781 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
782 p_vcdplayer->track[i].start_LSN =
783 vcdinfo_get_track_lsn(p_vcdobj, track_num);
786 p_vcdplayer->track = NULL;
788 if ( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
789 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
790 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
792 for (i=0; i<p_vcdplayer->i_entries; i++) {
793 p_vcdplayer->entry[i].size =
794 vcdinfo_get_entry_sect_count(p_vcdobj, i);
795 p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lsn(p_vcdobj, i);
798 p_vcdplayer->entry = NULL;
800 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
801 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
802 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
804 for (i=0; i<p_vcdplayer->i_segments; i++) {
805 p_vcdplayer->segment[i].size =
806 vcdinfo_get_seg_sector_count(p_vcdobj, i);
807 p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
810 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 bool play_single_item = 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 = 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_vcdplayer->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
881 p_access->p_sys = (access_sys_t *) p_vcdplayer;
883 /* Set where to log errors messages from libcdio. */
884 p_vcd_access = p_access;
885 cdio_log_set_handler ( cdio_log_handler );
886 vcd_log_set_handler ( vcd_log_handler );
888 psz_source = VCDParse( p_access, &itemid, &play_single_item );
890 if ( NULL == psz_source )
893 return( VLC_EGENERIC );
896 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
897 psz_source, p_access->psz_path );
899 p_vcdplayer->psz_source = strdup(psz_source);
900 p_vcdplayer->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
901 "-blocks-per-read" );
902 p_vcdplayer->b_track_length = config_GetInt( p_this, MODULE_STRING
904 p_vcdplayer->in_still = false;
905 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
906 p_vcdplayer->p_input = 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 )) )
920 p_vcdplayer->b_svd= (bool) vcdinfo_get_tracksSVD(p_vcdplayer->vcd);;
922 /* Get track information. */
923 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
925 if( p_vcdplayer->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcdplayer->i_tracks ) {
926 vcdinfo_close( p_vcdplayer->vcd );
927 LOG_ERR ("no movie tracks found" );
931 /* Build Navigation Title table for the tracks. */
932 VCDTitles( p_access );
934 /* Add into the above entry points as "Chapters". */
935 if( ! VCDEntryPoints( p_access ) )
937 msg_Warn( p_access, "could not read entry points, will not use them" );
938 p_vcdplayer->b_valid_ep = false;
941 /* Initialize LID info and add that as a menu item */
942 if( ! VCDLIDs( p_access ) )
944 msg_Warn( p_access, "could not read entry LIDs" );
947 /* Do we set PBC (via LID) on? */
949 ( VCDINFO_ITEM_TYPE_LID == itemid.type
950 && p_vcdplayer->i_lids > itemid.num )
952 : VCDINFO_INVALID_ENTRY;
954 /* Initialize segment information and add that a "Track". */
955 VCDSegments( p_access );
957 vcdplayer_play( p_access, itemid );
959 p_access->psz_demux = strdup( "ps" );
962 if (play_single_item)
963 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 = false;
971 p_vcdplayer->p_access = p_access;
974 intf_RunThread( p_vcdplayer->p_intf );
981 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
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" );
1000 for (i=0 ; i<p_vcdplayer->i_titles; i++)
1001 if (p_vcdplayer->p_title[i])
1002 free(p_vcdplayer->p_title[i]->psz_name);
1005 vcdinfo_close( p_vcdplayer->vcd );
1007 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
1009 FREENULL( p_vcdplayer->p_entries );
1010 FREENULL( p_vcdplayer->p_segments );
1011 FREENULL( p_vcdplayer->psz_source );
1012 FREENULL( p_vcdplayer->track );
1013 FREENULL( p_vcdplayer->segment );
1014 FREENULL( p_vcdplayer->entry );
1015 FREENULL( p_access->psz_demux );
1016 FREENULL( p_vcdplayer );
1017 p_vcd_access = NULL;
1020 /*****************************************************************************
1021 * Control: The front-end or vlc engine calls here to ether get
1022 * information such as meta information or plugin capabilities or to
1023 * issue miscellaneous "set" requests.
1024 *****************************************************************************/
1025 static int VCDControl( access_t *p_access, int i_query, va_list args )
1027 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1031 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1032 "query %d", i_query );
1036 /* Pass back a copy of meta information that was gathered when we
1037 during the Open/Initialize call.
1039 case ACCESS_GET_META:
1041 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1043 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1045 if( p_vcdplayer->p_meta )
1047 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1048 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1052 msg_Warn( p_access, "tried to copy NULL meta info" );
1056 return VLC_EGENERIC;
1058 case ACCESS_CAN_SEEK:
1059 case ACCESS_CAN_FASTSEEK:
1060 case ACCESS_CAN_PAUSE:
1061 case ACCESS_CAN_CONTROL_PACE:
1063 bool *pb_bool = (bool*)va_arg( args, bool* );
1065 dbg_print( INPUT_DBG_EVENT,
1066 "seek/fastseek/pause/can_control_pace" );
1073 case ACCESS_GET_MTU:
1074 pi_int = (int*)va_arg( args, int * );
1075 *pi_int = (p_vcdplayer->i_blocks_per_read * M2F2_SECTOR_SIZE);
1076 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1079 case ACCESS_GET_PTS_DELAY:
1081 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1082 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1083 * MILLISECONDS_PER_SEC;
1084 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1090 case ACCESS_SET_PAUSE_STATE:
1091 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1095 case ACCESS_GET_TITLE_INFO:
1097 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1098 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1099 input_title_t ***ppp_title
1100 = (input_title_t***)va_arg( args, input_title_t*** );
1101 char *psz_mrl = malloc( psz_mrl_max );
1104 pi_int = (int*)va_arg( args, int* );
1106 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1107 p_vcdplayer->i_titles );
1109 if( psz_mrl == NULL ) {
1110 msg_Warn( p_access, "out of memory" );
1112 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1113 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1114 VCDMetaInfo( p_access, psz_mrl );
1118 /* Duplicate title info */
1119 if( p_vcdplayer->i_titles == 0 )
1121 *pi_int = 0; ppp_title = NULL;
1124 *pi_int = p_vcdplayer->i_titles;
1125 *ppp_title = malloc( sizeof( input_title_t **)
1126 * p_vcdplayer->i_titles );
1128 if (!*ppp_title) return VLC_ENOMEM;
1130 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1132 if ( p_vcdplayer->p_title[i] )
1134 vlc_input_title_Duplicate( p_vcdplayer->p_title[i] );
1139 case ACCESS_SET_TITLE:
1140 i = (int)va_arg( args, int );
1142 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1143 if( i != p_access->info.i_title )
1145 vcdinfo_itemid_t itemid;
1146 track_t i_track = i+1;
1147 unsigned int i_entry =
1148 vcdinfo_track_get_entry( p_vcdplayer->vcd, i_track);
1150 if( i < p_vcdplayer->i_tracks )
1152 /* FIXME! For now we are assuming titles are only
1153 tracks and that track == title+1 */
1154 itemid.num = i_track;
1155 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1159 /* FIXME! i_tracks+2 are Segments, but we need to
1160 be able to figure out which segment of that.
1161 i_tracks+1 is either Segments (if no LIDs) or
1162 LIDs otherwise. Again need a way to get the LID
1165 "Trying to set track (%u) beyond end of last track (%u).",
1166 i+1, p_vcdplayer->i_tracks );
1167 return VLC_EGENERIC;
1170 VCDSetOrigin(p_access,
1171 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry),
1176 case ACCESS_SET_SEEKPOINT:
1178 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1179 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1181 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1182 if( t->i_seekpoint > 0 )
1184 track_t i_track = p_access->info.i_title+1;
1187 /* FIXME! For now we are assuming titles are only
1188 tracks and that track == title+1 and we the play
1189 item is entries (not tracks or lids).
1190 We need to generalize all of this.
1193 if (i < p_vcdplayer->i_entries)
1195 p_vcdplayer->play_item.num = i;
1196 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1197 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1198 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1200 p_vcdplayer->play_item.num = i
1201 = i - p_vcdplayer->i_entries;
1202 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1206 p_vcdplayer->play_item.num = i
1207 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1208 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1209 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1212 VCDSetOrigin( p_access,
1213 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i),
1214 i_track, &(p_vcdplayer->play_item) );
1219 case ACCESS_SET_PRIVATE_ID_STATE:
1220 dbg_print( INPUT_DBG_EVENT, "set private id" );
1221 return VLC_EGENERIC;
1224 msg_Warn( p_access, "unimplemented query in control" );
1225 return VLC_EGENERIC;