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 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_interface.h>
38 #include <vlc_input.h>
39 #include <vlc_access.h>
40 #include <vlc_charset.h>
43 #include <cdio/cdio.h>
44 #include <cdio/cd_types.h>
45 #include <cdio/logging.h>
46 #include <cdio/util.h>
47 #include <libvcd/info.h>
48 #include <libvcd/logging.h>
53 extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
54 const vcdinfo_itemid_t *p_itemid );
56 /*****************************************************************************
58 *****************************************************************************/
60 /* First those which are accessed from outside (via pointers). */
61 static block_t *VCDReadBlock ( access_t * );
63 static int VCDControl ( access_t *p_access, int i_query,
66 /* Now those which are strictly internal */
67 static bool VCDEntryPoints ( access_t * );
68 static bool VCDLIDs ( access_t * );
69 static bool VCDSegments ( access_t * );
70 static int VCDTitles ( access_t * );
71 static char *VCDParse ( access_t *,
72 /*out*/ vcdinfo_itemid_t * p_itemid ,
73 /*out*/ bool *play_single_item );
75 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
76 const char *p_varname, char *p_label,
77 const char *p_debug_label );
79 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
81 /****************************************************************************
83 ****************************************************************************/
85 /* FIXME: This variable is a hack. Would be nice to eliminate the
88 static access_t *p_vcd_access = NULL;
90 /* process messages that originate from libcdio. */
92 cdio_log_handler (cdio_log_level_t level, const char message[])
94 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
98 if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
99 msg_Dbg( p_vcd_access, "%s", message);
102 msg_Warn( p_vcd_access, "%s", message);
105 case CDIO_LOG_ASSERT:
106 msg_Err( p_vcd_access, "%s", message);
109 msg_Warn( p_vcd_access, "%s\n%s %d", message,
110 _("The above message had unknown log level"),
116 /* process messages that originate from vcdinfo. */
118 vcd_log_handler (vcd_log_level_t level, const char message[])
120 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
124 if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
125 msg_Dbg( p_vcd_access, "%s", message);
128 msg_Warn( p_vcd_access, "%s", message);
132 msg_Err( p_vcd_access, "%s", message);
135 msg_Warn( p_vcd_access, "%s\n%s %d", message,
136 _("The above message had unknown vcdimager log level"),
142 /*****************************************************************************
143 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
144 NULL is returned if something went wrong.
145 *****************************************************************************/
147 VCDReadBlock( access_t * p_access )
149 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
150 const int i_blocks = p_vcdplayer->i_blocks_per_read;
157 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
158 (long unsigned int) p_vcdplayer->i_lsn );
160 /* Allocate a block for the reading */
161 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
163 msg_Err( p_access, "cannot get a new block of size: %i",
164 i_blocks * M2F2_SECTOR_SIZE );
165 block_Release( p_block );
169 p_buf = (uint8_t *) p_block->p_buffer;
170 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
172 vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
174 p_access->info.i_pos += M2F2_SECTOR_SIZE;
176 switch ( read_status ) {
178 /* End reached. Return NULL to indicated this. */
179 /* We also set the postion to the end so the higher level
180 (demux?) doesn't try to keep reading. If everything works out
181 right this shouldn't have to happen.
184 if ( p_access->info.i_pos != p_access->info.i_size ) {
186 "At end but pos (%llu) is not size (%llu). Adjusting.",
187 p_access->info.i_pos, p_access->info.i_size );
188 p_access->info.i_pos = p_access->info.i_size;
192 block_Release( p_block );
196 /* Some sort of error. Should we increment lsn? to skip block?
198 block_Release( p_block );
200 case READ_STILL_FRAME:
202 /* FIXME The below should be done in an event thread.
206 msleep( MILLISECONDS_PER_SEC * *p_buf );
207 VCDSetOrigin(p_access, p_vcdplayer->origin_lsn, p_vcdplayer->i_track,
208 &(p_vcdplayer->play_item));
209 // p_vcd->in_still = false;
210 dbg_print(INPUT_DBG_STILL, "still wait time done");
212 vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);
215 block_Release( p_block );
225 p_buf += M2F2_SECTOR_SIZE;
226 /* Update seekpoint */
227 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
229 unsigned int i_entry = p_vcdplayer->play_item.num+1;
230 lsn_t i_lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
231 if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
233 const track_t i_track = p_vcdplayer->i_track;
235 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
236 "entry change to %d, current LSN %u >= end %u",
237 i_entry, p_vcdplayer->i_lsn, i_lsn);
239 p_vcdplayer->play_item.num = i_entry;
241 VCDSetOrigin( p_access, i_lsn, i_track,
242 &(p_vcdplayer->play_item) );
251 /****************************************************************************
253 ****************************************************************************/
255 VCDSeek( access_t * p_access, int64_t i_pos )
257 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
260 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
261 const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
262 unsigned int i_entry = VCDINFO_INVALID_ENTRY;
265 /* Next sector to read */
266 p_access->info.i_pos = i_pos;
267 p_vcdplayer->i_lsn = (i_pos / (int64_t) M2F2_SECTOR_SIZE) +
268 p_vcdplayer->origin_lsn;
270 switch (p_vcdplayer->play_item.type) {
271 case VCDINFO_ITEM_TYPE_TRACK:
272 case VCDINFO_ITEM_TYPE_ENTRY:
275 p_vcdplayer->b_valid_ep = false;
279 if( p_vcdplayer->b_valid_ep )
281 for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
283 if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
285 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
286 "chapter", _("Entry"), "Setting entry" );
292 vcdinfo_itemid_t itemid;
293 itemid.num = i_entry;
294 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
295 VCDSetOrigin(p_access, p_vcdplayer->i_lsn, p_vcdplayer->i_track,
300 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
301 "orig %lu, cur: %lu, offset: %lld, entry %d",
302 (long unsigned int) p_vcdplayer->origin_lsn,
303 (long unsigned int) p_vcdplayer->i_lsn, i_pos,
307 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
309 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
310 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
313 /* Update current seekpoint */
314 if( i_seekpoint != p_access->info.i_seekpoint )
316 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
317 (long unsigned int) i_seekpoint );
318 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
319 p_access->info.i_seekpoint = i_seekpoint;
323 p_access->info.b_eof = false;
328 /*****************************************************************************
329 VCDEntryPoints: Reads the information about the entry points on the disc
330 and initializes area information with that.
331 Before calling this track information should have been read in.
332 *****************************************************************************/
334 VCDEntryPoints( access_t * p_access )
336 if (!p_access || !p_access->p_sys) return false;
339 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
340 const unsigned int i_entries =
341 vcdinfo_get_num_entries(p_vcdplayer->vcd);
342 const track_t i_last_track
343 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
344 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
347 if (0 == i_entries) {
348 LOG_ERR ("no entires found -- something is wrong" );
352 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
354 if( p_vcdplayer->p_entries == NULL )
356 LOG_ERR ("not enough memory for entry points treatment" );
360 p_vcdplayer->i_entries = i_entries;
362 for( i = 0 ; i < i_entries ; i++ )
364 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
365 if( i_track <= i_last_track ) {
366 seekpoint_t *s = vlc_seekpoint_New();
369 snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i );
371 p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
373 s->psz_name = strdup(psz_entry);
375 (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track))
378 dbg_print( INPUT_DBG_MRL,
379 "%s, lsn %d, byte_offset %ld",
380 s->psz_name, p_vcdplayer->p_entries[i],
381 (unsigned long int) s->i_byte_offset);
382 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
383 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
386 msg_Warn( p_access, "wrong track number found in entry points" );
388 p_vcdplayer->b_valid_ep = true;
393 /*****************************************************************************
394 * VCDSegments: Reads the information about the segments the disc.
395 *****************************************************************************/
397 VCDSegments( access_t * p_access )
399 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
403 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
405 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
406 "Segments: %d", p_vcdplayer->i_segments);
408 if ( 0 == p_vcdplayer->i_segments ) return false;
410 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
411 p_vcdplayer->i_titles++;
413 t->i_size = 0; /* Not sure Segments have a size associated */
414 t->psz_name = strdup(_("Segments"));
416 /* We have one additional segment allocated so we can get the size
417 by subtracting seg[i+1] - seg[i].
419 p_vcdplayer->p_segments =
420 malloc( sizeof( lsn_t ) * (p_vcdplayer->i_segments+1) );
421 if( p_vcdplayer->p_segments == NULL )
423 LOG_ERR ("not enough memory for segment treatment" );
427 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
429 char psz_segment[100];
430 seekpoint_t *s = vlc_seekpoint_New();
431 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
433 snprintf( psz_segment, sizeof(psz_segment), "%s %02d", _("Segment"),
436 s->i_byte_offset = 0; /* Not sure what this would mean here */
437 s->psz_name = strdup(psz_segment);
438 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
441 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
442 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
443 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
444 p_vcdplayer->i_segments-1);
449 /*****************************************************************************
450 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
452 We start area addressing for tracks at 1 since the default area 0
453 is reserved for segments.
454 *****************************************************************************/
456 VCDTitles( access_t * p_access )
458 /* We'll assume a VCD has its first MPEG track
459 cdio_get_first_track_num()+1 could be used if one wanted to be
460 very careful about this. Note: cdio_get_first_track() will give the
461 ISO-9660 track before the MPEG tracks.
464 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
467 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
470 p_vcdplayer->i_titles = 0;
471 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
473 input_title_t *t = p_vcdplayer->p_title[i-1] =
474 vlc_input_title_New();
477 snprintf( psz_track, sizeof(psz_track), "%s %02d", _("Track"),
479 t->i_size = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
481 * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
482 t->psz_name = strdup(psz_track);
484 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld", i, t->i_size );
486 p_vcdplayer->i_titles++;
493 /*****************************************************************************
494 VCDLIDs: Reads the LIST IDs from the LOT.
495 *****************************************************************************/
497 VCDLIDs( access_t * p_access )
499 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
501 unsigned int i_lid, i_title;
503 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
504 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
506 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
507 "LIDs: %d", p_vcdplayer->i_lids);
509 if ( 0 == p_vcdplayer->i_lids ) return false;
511 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
513 vcdinfo_visit_lot (p_vcdplayer->vcd, false);
517 We need to change libvcdinfo to be more robust when there are
518 problems reading the extended PSD. Given that area-highlighting and
519 selection features in the extended PSD haven't been implemented,
520 it's best then to not try to read this at all.
522 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
523 vcdinfo_visit_lot (p_vcdplayer->vcd, true);
527 /* Set up LIDs Navigation Menu */
528 t = vlc_input_title_New();
530 t->psz_name = strdup( "LIDs" );
532 i_title = p_vcdplayer->i_tracks;
533 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
536 seekpoint_t *s = vlc_seekpoint_New();
538 snprintf( psz_lid, sizeof(psz_lid), "%s %02d", _("LID"),
541 s->i_byte_offset = 0; /* A lid doesn't have an offset
542 size associated with it */
543 s->psz_name = strdup(psz_lid);
544 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
547 #if DYNAMICALLY_ALLOCATED
548 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
550 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
551 p_vcdplayer->i_titles++;
557 /*****************************************************************************
558 * VCDParse: parse command line
559 *****************************************************************************/
561 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
562 /*out*/ bool *play_single_item )
564 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
569 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
570 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
572 *play_single_item = false;
576 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
581 /* On Win32 we want the VCD access plugin to be explicitly requested,
582 * we end up with lots of problems otherwise */
583 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
586 if( !p_access->psz_path )
591 psz_parser = psz_source = strdup( p_access->psz_path );
593 /* Parse input string :
594 * [device][@[type][title]] */
595 while( *psz_parser && *psz_parser != '@' )
600 if( *psz_parser == '@' )
602 /* Found the divide between the source name and the
603 type+entry number. */
610 switch(*psz_parser) {
612 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
614 *play_single_item = true;
617 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
619 *play_single_item = false;
622 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
624 *play_single_item = true;
627 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
629 *play_single_item = true;
635 num = strtol( psz_parser, &psz_next, 10 );
636 if ( *psz_parser != '\0' && *psz_next == '\0')
642 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
648 /* No source specified, so figure it out. */
649 if( !p_access->psz_access ) return NULL;
651 psz_source = config_GetPsz( p_access, "vcd" );
653 if( !psz_source || 0==strlen(psz_source) ) {
654 /* Scan for a CD-ROM drive with a VCD in it. */
655 char **cd_drives = cdio_get_devices_with_cap( NULL,
656 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
657 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
659 if( NULL == cd_drives ) return NULL;
660 if( cd_drives[0] == NULL )
662 cdio_free_device_list( cd_drives );
665 psz_source = strdup( cd_drives[0] );
666 cdio_free_device_list( cd_drives );
670 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
671 "source=%s entry=%d type=%d",
672 psz_source, p_itemid->num, p_itemid->type);
678 Sets start origin for subsequent seeks/reads
681 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
682 const vcdinfo_itemid_t *p_itemid )
684 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
686 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
687 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
690 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
692 switch (p_vcdplayer->play_item.type) {
693 case VCDINFO_ITEM_TYPE_ENTRY:
694 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
695 "chapter", _("Entry"), "Setting entry/segment");
696 p_access->info.i_title = i_track-1;
697 if (p_vcdplayer->b_track_length)
699 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
700 p_access->info.i_pos = (int64_t) M2F2_SECTOR_SIZE *
701 (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track) - i_lsn) ;
703 p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
704 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd, p_itemid->num);
705 p_access->info.i_pos = 0;
707 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %llu, pos: %llu",
708 p_access->info.i_size, p_access->info.i_pos );
709 p_access->info.i_seekpoint = p_itemid->num;
712 case VCDINFO_ITEM_TYPE_SEGMENT:
713 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
714 "chapter", _("Segment"), "Setting entry/segment");
715 /* The last title entry is the for segments (when segments exist
716 and they must here. The segment seekpoints are stored after
717 the entry seekpoints and (zeroed) lid seekpoints.
719 p_access->info.i_title = p_vcdplayer->i_titles - 1;
720 p_access->info.i_size = 0; /* No seeking on stills, please. */
721 p_access->info.i_pos = 0;
722 p_access->info.i_seekpoint = p_vcdplayer->i_entries
723 + p_vcdplayer->i_lids + p_itemid->num;
726 case VCDINFO_ITEM_TYPE_TRACK:
727 p_access->info.i_title = i_track-1;
728 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
729 p_access->info.i_pos = 0;
730 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 );
739 p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
740 | INPUT_UPDATE_SEEKPOINT;
742 VCDUpdateTitle( p_access );
746 /*****************************************************************************
747 * vcd_Open: Opens a VCD device or file initializes, a list of
748 tracks, segements and entry lsns and sizes and returns an opaque handle.
749 *****************************************************************************/
750 static vcdinfo_obj_t *
751 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
753 access_t *p_access = (access_t *)p_this;
754 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
755 vcdinfo_obj_t *p_vcdobj;
759 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
761 if( !psz_dev ) return NULL;
763 actual_dev= ToLocaleDup(psz_dev);
764 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
772 Save summary info on tracks, segments and entries...
775 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
776 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
777 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
779 for (i=0; i<p_vcdplayer->i_tracks; i++) {
780 unsigned int track_num=i+1;
781 p_vcdplayer->track[i].size =
782 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
783 p_vcdplayer->track[i].start_LSN =
784 vcdinfo_get_track_lsn(p_vcdobj, track_num);
787 p_vcdplayer->track = NULL;
789 if ( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
790 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
791 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
793 for (i=0; i<p_vcdplayer->i_entries; i++) {
794 p_vcdplayer->entry[i].size =
795 vcdinfo_get_entry_sect_count(p_vcdobj, i);
796 p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lsn(p_vcdobj, i);
799 p_vcdplayer->entry = NULL;
801 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
802 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
803 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
805 for (i=0; i<p_vcdplayer->i_segments; i++) {
806 p_vcdplayer->segment[i].size =
807 vcdinfo_get_seg_sector_count(p_vcdobj, i);
808 p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
811 p_vcdplayer->segment = NULL;
816 /****************************************************************************
817 Update the "varname" variable to i_num without triggering a callback.
818 ****************************************************************************/
820 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
821 const char *p_varname, char *p_label,
822 const char *p_debug_label)
827 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
828 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
832 text.psz_string = p_label;
833 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
835 var_Change( p_access, p_varname, i_action, &val, NULL );
839 /*****************************************************************************
841 *****************************************************************************/
843 /*****************************************************************************
845 read in meta-information about VCD: the number of tracks, segments,
846 entries, size and starting information. Then set up state variables so
847 that we read/seek starting at the location specified.
849 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
850 and VLC_EGENERIC for some other error.
851 *****************************************************************************/
853 VCDOpen ( vlc_object_t *p_this )
855 access_t *p_access = (access_t *)p_this;
856 vcdplayer_t *p_vcdplayer;
858 vcdinfo_itemid_t itemid;
859 bool play_single_item = false;
861 p_access->pf_read = NULL;
862 p_access->pf_block = VCDReadBlock;
863 p_access->pf_control = VCDControl;
864 p_access->pf_seek = VCDSeek;
866 p_access->info.i_update = 0;
867 p_access->info.i_size = 0;
868 p_access->info.i_pos = 0;
869 p_access->info.b_eof = false;
870 p_access->info.i_title = 0;
871 p_access->info.i_seekpoint = 0;
873 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
875 if( p_vcdplayer == NULL )
877 LOG_ERR ("out of memory" );
881 p_vcdplayer->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
882 p_access->p_sys = (access_sys_t *) p_vcdplayer;
884 /* Set where to log errors messages from libcdio. */
885 p_vcd_access = p_access;
886 cdio_log_set_handler ( cdio_log_handler );
887 vcd_log_set_handler ( vcd_log_handler );
889 psz_source = VCDParse( p_access, &itemid, &play_single_item );
891 if ( NULL == psz_source )
894 return( VLC_EGENERIC );
897 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
898 psz_source, p_access->psz_path );
900 p_vcdplayer->psz_source = strdup(psz_source);
901 p_vcdplayer->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
902 "-blocks-per-read" );
903 p_vcdplayer->b_track_length = config_GetInt( p_this, MODULE_STRING
905 p_vcdplayer->in_still = false;
906 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
907 p_vcdplayer->p_input = vlc_object_find( p_access,
910 // p_vcdplayer->p_meta = vlc_meta_New();
911 p_vcdplayer->p_segments = NULL;
912 p_vcdplayer->p_entries = NULL;
916 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
921 p_vcdplayer->b_svd= (bool) 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 = 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 free( p_access->psz_demux );
961 p_access->psz_demux = strdup( "ps" );
964 if (play_single_item)
965 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 = false;
973 p_vcdplayer->p_access = p_access;
976 intf_RunThread( p_vcdplayer->p_intf );
983 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
989 /*****************************************************************************
990 * VCDClose: closes VCD releasing allocated memory.
991 *****************************************************************************/
993 VCDClose ( vlc_object_t *p_this )
995 access_t *p_access = (access_t *)p_this;
996 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
998 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1002 for (i=0 ; i<p_vcdplayer->i_titles; i++)
1003 if (p_vcdplayer->p_title[i])
1004 free(p_vcdplayer->p_title[i]->psz_name);
1007 vcdinfo_close( p_vcdplayer->vcd );
1009 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
1011 FREENULL( p_vcdplayer->p_entries );
1012 FREENULL( p_vcdplayer->p_segments );
1013 FREENULL( p_vcdplayer->psz_source );
1014 FREENULL( p_vcdplayer->track );
1015 FREENULL( p_vcdplayer->segment );
1016 FREENULL( p_vcdplayer->entry );
1017 FREENULL( p_access->psz_demux );
1018 FREENULL( p_vcdplayer );
1019 p_vcd_access = NULL;
1022 /*****************************************************************************
1023 * Control: The front-end or vlc engine calls here to ether get
1024 * information such as meta information or plugin capabilities or to
1025 * issue miscellaneous "set" requests.
1026 *****************************************************************************/
1027 static int VCDControl( access_t *p_access, int i_query, va_list args )
1029 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1033 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1034 "query %d", i_query );
1038 /* Pass back a copy of meta information that was gathered when we
1039 during the Open/Initialize call.
1041 case ACCESS_GET_META:
1043 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1045 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1047 if( p_vcdplayer->p_meta )
1049 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1050 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1054 msg_Warn( p_access, "tried to copy NULL meta info" );
1058 return VLC_EGENERIC;
1060 case ACCESS_CAN_SEEK:
1061 case ACCESS_CAN_FASTSEEK:
1062 case ACCESS_CAN_PAUSE:
1063 case ACCESS_CAN_CONTROL_PACE:
1065 bool *pb_bool = (bool*)va_arg( args, bool* );
1067 dbg_print( INPUT_DBG_EVENT,
1068 "seek/fastseek/pause/can_control_pace" );
1075 case ACCESS_GET_MTU:
1076 pi_int = (int*)va_arg( args, int * );
1077 *pi_int = (p_vcdplayer->i_blocks_per_read * M2F2_SECTOR_SIZE);
1078 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1081 case ACCESS_GET_PTS_DELAY:
1083 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1084 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1085 * MILLISECONDS_PER_SEC;
1086 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1092 case ACCESS_SET_PAUSE_STATE:
1093 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1097 case ACCESS_GET_TITLE_INFO:
1099 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1100 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1101 input_title_t ***ppp_title
1102 = (input_title_t***)va_arg( args, input_title_t*** );
1103 char *psz_mrl = malloc( psz_mrl_max );
1106 pi_int = (int*)va_arg( args, int* );
1108 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1109 p_vcdplayer->i_titles );
1111 if( psz_mrl == NULL ) {
1112 msg_Warn( p_access, "out of memory" );
1114 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1115 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1116 VCDMetaInfo( p_access, psz_mrl );
1120 /* Duplicate title info */
1121 if( p_vcdplayer->i_titles == 0 )
1123 *pi_int = 0; ppp_title = NULL;
1126 *pi_int = p_vcdplayer->i_titles;
1127 *ppp_title = malloc( sizeof( input_title_t **)
1128 * p_vcdplayer->i_titles );
1130 if (!*ppp_title) return VLC_ENOMEM;
1132 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1134 if ( p_vcdplayer->p_title[i] )
1136 vlc_input_title_Duplicate( p_vcdplayer->p_title[i] );
1141 case ACCESS_SET_TITLE:
1142 i = (int)va_arg( args, int );
1144 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1145 if( i != p_access->info.i_title )
1147 vcdinfo_itemid_t itemid;
1148 track_t i_track = i+1;
1149 unsigned int i_entry =
1150 vcdinfo_track_get_entry( p_vcdplayer->vcd, i_track);
1152 if( i < p_vcdplayer->i_tracks )
1154 /* FIXME! For now we are assuming titles are only
1155 tracks and that track == title+1 */
1156 itemid.num = i_track;
1157 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1161 /* FIXME! i_tracks+2 are Segments, but we need to
1162 be able to figure out which segment of that.
1163 i_tracks+1 is either Segments (if no LIDs) or
1164 LIDs otherwise. Again need a way to get the LID
1167 "Trying to set track (%u) beyond end of last track (%u).",
1168 i+1, p_vcdplayer->i_tracks );
1169 return VLC_EGENERIC;
1172 VCDSetOrigin(p_access,
1173 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry),
1178 case ACCESS_SET_SEEKPOINT:
1180 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1181 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1183 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1184 if( t->i_seekpoint > 0 )
1186 track_t i_track = p_access->info.i_title+1;
1189 /* FIXME! For now we are assuming titles are only
1190 tracks and that track == title+1 and we the play
1191 item is entries (not tracks or lids).
1192 We need to generalize all of this.
1195 if (i < p_vcdplayer->i_entries)
1197 p_vcdplayer->play_item.num = i;
1198 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1199 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1200 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1202 p_vcdplayer->play_item.num = i
1203 = i - p_vcdplayer->i_entries;
1204 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1208 p_vcdplayer->play_item.num = i
1209 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1210 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1211 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1214 VCDSetOrigin( p_access,
1215 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i),
1216 i_track, &(p_vcdplayer->play_item) );
1221 case ACCESS_SET_PRIVATE_ID_STATE:
1222 dbg_print( INPUT_DBG_EVENT, "set private id" );
1223 return VLC_EGENERIC;
1226 msg_Warn( p_access, "unimplemented query in control" );
1227 return VLC_EGENERIC;