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 /*****************************************************************************
55 *****************************************************************************/
57 /* First those which are accessed from outside (via pointers). */
58 static block_t *VCDReadBlock ( access_t * );
60 static int VCDControl ( access_t *p_access, int i_query,
63 /* Now those which are strictly internal */
64 static bool VCDEntryPoints ( access_t * );
65 static bool VCDLIDs ( access_t * );
66 static bool VCDSegments ( access_t * );
67 static int VCDTitles ( access_t * );
68 static char *VCDParse ( access_t *,
69 /*out*/ vcdinfo_itemid_t * p_itemid ,
70 /*out*/ bool *play_single_item );
72 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
73 const char *p_varname, char *p_label,
74 const char *p_debug_label );
76 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
78 /****************************************************************************
80 ****************************************************************************/
82 /* FIXME: This variable is a hack. Would be nice to eliminate the
85 static access_t *p_vcd_access = NULL;
87 /* process messages that originate from libcdio. */
89 cdio_log_handler (cdio_log_level_t level, const char message[])
91 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
95 if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
96 msg_Dbg( p_vcd_access, "%s", message);
99 msg_Warn( p_vcd_access, "%s", message);
102 case CDIO_LOG_ASSERT:
103 msg_Err( p_vcd_access, "%s", message);
106 msg_Warn( p_vcd_access, "%s\n%s %d", message,
107 "The above message had unknown log level",
113 /* process messages that originate from vcdinfo. */
115 vcd_log_handler (vcd_log_level_t level, const char message[])
117 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
121 if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
122 msg_Dbg( p_vcd_access, "%s", message);
125 msg_Warn( p_vcd_access, "%s", message);
129 msg_Err( p_vcd_access, "%s", message);
132 msg_Warn( p_vcd_access, "%s\n%s %d", message,
133 "The above message had unknown vcdimager log level",
139 /*****************************************************************************
140 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
141 NULL is returned if something went wrong.
142 *****************************************************************************/
144 VCDReadBlock( access_t * p_access )
146 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
147 const int i_blocks = p_vcdplayer->i_blocks_per_read;
154 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
155 (long unsigned int) p_vcdplayer->i_lsn );
157 /* Allocate a block for the reading */
158 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
160 msg_Err( p_access, "cannot get a new block of size: %i",
161 i_blocks * M2F2_SECTOR_SIZE );
162 block_Release( p_block );
166 p_buf = (uint8_t *) p_block->p_buffer;
167 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
169 vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
171 p_access->info.i_pos += M2F2_SECTOR_SIZE;
173 switch ( read_status ) {
175 /* End reached. Return NULL to indicated this. */
176 /* We also set the postion to the end so the higher level
177 (demux?) doesn't try to keep reading. If everything works out
178 right this shouldn't have to happen.
181 if ( p_access->info.i_pos != p_access->info.i_size ) {
183 "At end but pos (%llu) is not size (%llu). Adjusting.",
184 p_access->info.i_pos, p_access->info.i_size );
185 p_access->info.i_pos = p_access->info.i_size;
189 block_Release( p_block );
193 /* Some sort of error. Should we increment lsn? to skip block?
195 block_Release( p_block );
197 case READ_STILL_FRAME:
199 /* FIXME The below should be done in an event thread.
203 msleep( MILLISECONDS_PER_SEC * *p_buf );
204 VCDSetOrigin(p_access, p_vcdplayer->origin_lsn, p_vcdplayer->i_track,
205 &(p_vcdplayer->play_item));
206 // p_vcd->in_still = false;
207 dbg_print(INPUT_DBG_STILL, "still wait time done");
209 vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);
212 block_Release( p_block );
222 p_buf += M2F2_SECTOR_SIZE;
223 /* Update seekpoint */
224 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
226 unsigned int i_entry = p_vcdplayer->play_item.num+1;
227 lsn_t i_lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
228 if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
230 const track_t i_track = p_vcdplayer->i_track;
232 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
233 "entry change to %d, current LSN %u >= end %u",
234 i_entry, p_vcdplayer->i_lsn, i_lsn);
236 p_vcdplayer->play_item.num = i_entry;
238 VCDSetOrigin( p_access, i_lsn, i_track,
239 &(p_vcdplayer->play_item) );
248 /****************************************************************************
250 ****************************************************************************/
252 VCDSeek( access_t * p_access, int64_t i_pos )
254 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
257 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
258 const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
259 unsigned int i_entry = VCDINFO_INVALID_ENTRY;
262 /* Next sector to read */
263 p_access->info.i_pos = i_pos;
264 p_vcdplayer->i_lsn = (i_pos / (int64_t) M2F2_SECTOR_SIZE) +
265 p_vcdplayer->origin_lsn;
267 switch (p_vcdplayer->play_item.type) {
268 case VCDINFO_ITEM_TYPE_TRACK:
269 case VCDINFO_ITEM_TYPE_ENTRY:
272 p_vcdplayer->b_valid_ep = false;
276 if( p_vcdplayer->b_valid_ep )
278 for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
280 if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
282 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
283 "chapter", _("Entry"), "Setting entry" );
289 vcdinfo_itemid_t itemid;
290 itemid.num = i_entry;
291 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
292 VCDSetOrigin(p_access, p_vcdplayer->i_lsn, p_vcdplayer->i_track,
297 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
298 "orig %lu, cur: %lu, offset: %lld, entry %d",
299 (long unsigned int) p_vcdplayer->origin_lsn,
300 (long unsigned int) p_vcdplayer->i_lsn, i_pos,
304 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
306 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
307 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
310 /* Update current seekpoint */
311 if( i_seekpoint != p_access->info.i_seekpoint )
313 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
314 (long unsigned int) i_seekpoint );
315 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
316 p_access->info.i_seekpoint = i_seekpoint;
320 p_access->info.b_eof = false;
325 /*****************************************************************************
326 VCDEntryPoints: Reads the information about the entry points on the disc
327 and initializes area information with that.
328 Before calling this track information should have been read in.
329 *****************************************************************************/
331 VCDEntryPoints( access_t * p_access )
333 if (!p_access || !p_access->p_sys) return false;
336 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
337 const unsigned int i_entries =
338 vcdinfo_get_num_entries(p_vcdplayer->vcd);
339 const track_t i_last_track
340 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
341 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
344 if (0 == i_entries) {
345 LOG_ERR ("no entires found -- something is wrong" );
349 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
351 if( p_vcdplayer->p_entries == NULL )
353 LOG_ERR ("not enough memory for entry points treatment" );
357 p_vcdplayer->i_entries = i_entries;
359 for( i = 0 ; i < i_entries ; i++ )
361 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
362 if( i_track <= i_last_track ) {
363 seekpoint_t *s = vlc_seekpoint_New();
366 snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i );
368 p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
370 s->psz_name = strdup(psz_entry);
372 (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track))
375 dbg_print( INPUT_DBG_MRL,
376 "%s, lsn %d, byte_offset %ld",
377 s->psz_name, p_vcdplayer->p_entries[i],
378 (unsigned long int) s->i_byte_offset);
379 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
380 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
383 msg_Warn( p_access, "wrong track number found in entry points" );
385 p_vcdplayer->b_valid_ep = true;
390 /*****************************************************************************
391 * VCDSegments: Reads the information about the segments the disc.
392 *****************************************************************************/
394 VCDSegments( access_t * p_access )
396 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
400 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
402 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
403 "Segments: %d", p_vcdplayer->i_segments);
405 if ( 0 == p_vcdplayer->i_segments ) return false;
407 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
408 p_vcdplayer->i_titles++;
410 t->i_size = 0; /* Not sure Segments have a size associated */
411 t->psz_name = strdup(_("Segments"));
413 /* We have one additional segment allocated so we can get the size
414 by subtracting seg[i+1] - seg[i].
416 p_vcdplayer->p_segments =
417 malloc( sizeof( lsn_t ) * (p_vcdplayer->i_segments+1) );
418 if( p_vcdplayer->p_segments == NULL )
420 LOG_ERR ("not enough memory for segment treatment" );
424 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
426 char psz_segment[100];
427 seekpoint_t *s = vlc_seekpoint_New();
428 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
430 snprintf( psz_segment, sizeof(psz_segment), "%s %02d", _("Segment"),
433 s->i_byte_offset = 0; /* Not sure what this would mean here */
434 s->psz_name = strdup(psz_segment);
435 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
438 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
439 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
440 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
441 p_vcdplayer->i_segments-1);
446 /*****************************************************************************
447 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
449 We start area addressing for tracks at 1 since the default area 0
450 is reserved for segments.
451 *****************************************************************************/
453 VCDTitles( access_t * p_access )
455 /* We'll assume a VCD has its first MPEG track
456 cdio_get_first_track_num()+1 could be used if one wanted to be
457 very careful about this. Note: cdio_get_first_track() will give the
458 ISO-9660 track before the MPEG tracks.
461 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
464 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
467 p_vcdplayer->i_titles = 0;
468 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
470 input_title_t *t = p_vcdplayer->p_title[i-1] =
471 vlc_input_title_New();
474 snprintf( psz_track, sizeof(psz_track), "%s %02d", _("Track"),
476 t->i_size = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
478 * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
479 t->psz_name = strdup(psz_track);
481 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld", i, t->i_size );
483 p_vcdplayer->i_titles++;
490 /*****************************************************************************
491 VCDLIDs: Reads the LIST IDs from the LOT.
492 *****************************************************************************/
494 VCDLIDs( access_t * p_access )
496 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
498 unsigned int i_lid, i_title;
500 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
501 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
503 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
504 "LIDs: %d", p_vcdplayer->i_lids);
506 if ( 0 == p_vcdplayer->i_lids ) return false;
508 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
510 vcdinfo_visit_lot (p_vcdplayer->vcd, false);
514 We need to change libvcdinfo to be more robust when there are
515 problems reading the extended PSD. Given that area-highlighting and
516 selection features in the extended PSD haven't been implemented,
517 it's best then to not try to read this at all.
519 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
520 vcdinfo_visit_lot (p_vcdplayer->vcd, true);
524 /* Set up LIDs Navigation Menu */
525 t = vlc_input_title_New();
527 t->psz_name = strdup( "LIDs" );
529 i_title = p_vcdplayer->i_tracks;
530 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
533 seekpoint_t *s = vlc_seekpoint_New();
535 snprintf( psz_lid, sizeof(psz_lid), "%s %02d", _("LID"),
538 s->i_byte_offset = 0; /* A lid doesn't have an offset
539 size associated with it */
540 s->psz_name = strdup(psz_lid);
541 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
544 #ifdef DYNAMICALLY_ALLOCATED
545 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
547 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
548 p_vcdplayer->i_titles++;
554 /*****************************************************************************
555 * VCDParse: parse command line
556 *****************************************************************************/
558 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
559 /*out*/ bool *play_single_item )
561 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
566 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
567 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
569 *play_single_item = false;
573 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
578 /* On Win32 we want the VCD access plugin to be explicitly requested,
579 * we end up with lots of problems otherwise */
580 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
583 if( !p_access->psz_path )
588 psz_parser = psz_source = strdup( p_access->psz_path );
590 /* Parse input string :
591 * [device][@[type][title]] */
592 while( *psz_parser && *psz_parser != '@' )
597 if( *psz_parser == '@' )
599 /* Found the divide between the source name and the
600 type+entry number. */
607 switch(*psz_parser) {
609 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
611 *play_single_item = true;
614 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
616 *play_single_item = false;
619 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
621 *play_single_item = true;
624 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
626 *play_single_item = true;
632 num = strtol( psz_parser, &psz_next, 10 );
633 if ( *psz_parser != '\0' && *psz_next == '\0')
639 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
645 /* No source specified, so figure it out. */
646 if( !p_access->psz_access ) return NULL;
648 psz_source = config_GetPsz( p_access, "vcd" );
650 if( !psz_source || 0==strlen(psz_source) ) {
652 /* Scan for a CD-ROM drive with a VCD in it. */
653 char **cd_drives = cdio_get_devices_with_cap( NULL,
654 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
655 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
657 if( NULL == cd_drives ) return NULL;
658 if( cd_drives[0] == NULL )
660 cdio_free_device_list( cd_drives );
663 psz_source = strdup( cd_drives[0] );
664 cdio_free_device_list( cd_drives );
668 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
669 "source=%s entry=%d type=%d",
670 psz_source, p_itemid->num, p_itemid->type);
676 Sets start origin for subsequent seeks/reads
679 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
680 const vcdinfo_itemid_t *p_itemid )
682 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
684 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
685 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
688 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
690 switch (p_vcdplayer->play_item.type) {
691 case VCDINFO_ITEM_TYPE_ENTRY:
692 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
693 "chapter", _("Entry"), "Setting entry/segment");
694 p_access->info.i_title = i_track-1;
695 if (p_vcdplayer->b_track_length)
697 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
698 p_access->info.i_pos = (int64_t) M2F2_SECTOR_SIZE *
699 (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track) - i_lsn) ;
701 p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
702 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd, p_itemid->num);
703 p_access->info.i_pos = 0;
705 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %llu, pos: %llu",
706 p_access->info.i_size, p_access->info.i_pos );
707 p_access->info.i_seekpoint = p_itemid->num;
710 case VCDINFO_ITEM_TYPE_SEGMENT:
711 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
712 "chapter", _("Segment"), "Setting entry/segment");
713 /* The last title entry is the for segments (when segments exist
714 and they must here. The segment seekpoints are stored after
715 the entry seekpoints and (zeroed) lid seekpoints.
717 p_access->info.i_title = p_vcdplayer->i_titles - 1;
718 p_access->info.i_size = 0; /* No seeking on stills, please. */
719 p_access->info.i_pos = 0;
720 p_access->info.i_seekpoint = p_vcdplayer->i_entries
721 + p_vcdplayer->i_lids + p_itemid->num;
724 case VCDINFO_ITEM_TYPE_TRACK:
725 p_access->info.i_title = i_track-1;
726 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
727 p_access->info.i_pos = 0;
728 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
733 msg_Warn( p_access, "can't set origin for play type %d",
734 p_vcdplayer->play_item.type );
737 p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
738 | INPUT_UPDATE_SEEKPOINT;
740 VCDUpdateTitle( p_access );
744 /*****************************************************************************
745 * vcd_Open: Opens a VCD device or file initializes, a list of
746 tracks, segements and entry lsns and sizes and returns an opaque handle.
747 *****************************************************************************/
748 static vcdinfo_obj_t *
749 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
751 access_t *p_access = (access_t *)p_this;
752 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
753 vcdinfo_obj_t *p_vcdobj;
757 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
759 if( !psz_dev ) return NULL;
761 actual_dev= ToLocaleDup(psz_dev);
762 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
770 Save summary info on tracks, segments and entries...
773 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
774 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
775 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
777 for (i=0; i<p_vcdplayer->i_tracks; i++) {
778 unsigned int track_num=i+1;
779 p_vcdplayer->track[i].size =
780 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
781 p_vcdplayer->track[i].start_LSN =
782 vcdinfo_get_track_lsn(p_vcdobj, track_num);
785 p_vcdplayer->track = NULL;
787 if ( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
788 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
789 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
791 for (i=0; i<p_vcdplayer->i_entries; i++) {
792 p_vcdplayer->entry[i].size =
793 vcdinfo_get_entry_sect_count(p_vcdobj, i);
794 p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lsn(p_vcdobj, i);
797 p_vcdplayer->entry = NULL;
799 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
800 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
801 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
803 for (i=0; i<p_vcdplayer->i_segments; i++) {
804 p_vcdplayer->segment[i].size =
805 vcdinfo_get_seg_sector_count(p_vcdobj, i);
806 p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
809 p_vcdplayer->segment = NULL;
814 /****************************************************************************
815 Update the "varname" variable to i_num without triggering a callback.
816 ****************************************************************************/
818 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
819 const char *p_varname, char *p_label,
820 const char *p_debug_label)
825 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
826 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
830 text.psz_string = p_label;
831 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
833 var_Change( p_access, p_varname, i_action, &val, NULL );
837 /*****************************************************************************
839 *****************************************************************************/
841 /*****************************************************************************
843 read in meta-information about VCD: the number of tracks, segments,
844 entries, size and starting information. Then set up state variables so
845 that we read/seek starting at the location specified.
847 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
848 and VLC_EGENERIC for some other error.
849 *****************************************************************************/
851 VCDOpen ( vlc_object_t *p_this )
853 access_t *p_access = (access_t *)p_this;
854 vcdplayer_t *p_vcdplayer;
856 vcdinfo_itemid_t itemid;
857 bool play_single_item = false;
859 p_access->pf_read = NULL;
860 p_access->pf_block = VCDReadBlock;
861 p_access->pf_control = VCDControl;
862 p_access->pf_seek = VCDSeek;
864 p_access->info.i_update = 0;
865 p_access->info.i_size = 0;
866 p_access->info.i_pos = 0;
867 p_access->info.b_eof = false;
868 p_access->info.i_title = 0;
869 p_access->info.i_seekpoint = 0;
871 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
873 if( p_vcdplayer == NULL )
876 p_vcdplayer->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
877 p_access->p_sys = (access_sys_t *) p_vcdplayer;
879 /* Set where to log errors messages from libcdio. */
880 p_vcd_access = p_access;
881 cdio_log_set_handler ( cdio_log_handler );
882 vcd_log_set_handler ( vcd_log_handler );
884 psz_source = VCDParse( p_access, &itemid, &play_single_item );
886 if ( NULL == psz_source )
889 return( VLC_EGENERIC );
892 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
893 psz_source, p_access->psz_path );
895 p_vcdplayer->psz_source = strdup(psz_source);
896 p_vcdplayer->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
897 "-blocks-per-read" );
898 p_vcdplayer->b_track_length = config_GetInt( p_this, MODULE_STRING
900 p_vcdplayer->in_still = false;
901 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
902 p_vcdplayer->p_input = vlc_object_find( p_access,
905 // p_vcdplayer->p_meta = vlc_meta_New();
906 p_vcdplayer->p_segments = NULL;
907 p_vcdplayer->p_entries = NULL;
911 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
916 p_vcdplayer->b_svd= (bool) vcdinfo_get_tracksSVD(p_vcdplayer->vcd);;
918 /* Get track information. */
919 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
921 if( p_vcdplayer->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcdplayer->i_tracks ) {
922 vcdinfo_close( p_vcdplayer->vcd );
923 LOG_ERR ("no movie tracks found" );
927 /* Build Navigation Title table for the tracks. */
928 VCDTitles( p_access );
930 /* Add into the above entry points as "Chapters". */
931 if( ! VCDEntryPoints( p_access ) )
933 msg_Warn( p_access, "could not read entry points, will not use them" );
934 p_vcdplayer->b_valid_ep = false;
937 /* Initialize LID info and add that as a menu item */
938 if( ! VCDLIDs( p_access ) )
940 msg_Warn( p_access, "could not read entry LIDs" );
943 /* Do we set PBC (via LID) on? */
945 ( VCDINFO_ITEM_TYPE_LID == itemid.type
946 && p_vcdplayer->i_lids > itemid.num )
948 : VCDINFO_INVALID_ENTRY;
950 /* Initialize segment information and add that a "Track". */
951 VCDSegments( p_access );
953 vcdplayer_play( p_access, itemid );
955 free( p_access->psz_demux );
956 p_access->psz_demux = strdup( "ps" );
959 if (play_single_item)
960 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
965 p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
966 p_vcdplayer->p_intf->b_block = false;
968 p_vcdplayer->p_access = p_access;
974 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
976 free( p_vcdplayer->psz_source );
981 /*****************************************************************************
982 * VCDClose: closes VCD releasing allocated memory.
983 *****************************************************************************/
985 VCDClose ( vlc_object_t *p_this )
987 access_t *p_access = (access_t *)p_this;
988 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
990 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
994 for (i=0 ; i<p_vcdplayer->i_titles; i++)
995 if (p_vcdplayer->p_title[i])
996 free(p_vcdplayer->p_title[i]->psz_name);
999 vcdinfo_close( p_vcdplayer->vcd );
1001 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
1003 FREENULL( p_vcdplayer->p_entries );
1004 FREENULL( p_vcdplayer->p_segments );
1005 FREENULL( p_vcdplayer->psz_source );
1006 FREENULL( p_vcdplayer->track );
1007 FREENULL( p_vcdplayer->segment );
1008 FREENULL( p_vcdplayer->entry );
1009 FREENULL( p_access->psz_demux );
1010 FREENULL( p_vcdplayer );
1011 p_vcd_access = NULL;
1014 /*****************************************************************************
1015 * Control: The front-end or vlc engine calls here to ether get
1016 * information such as meta information or plugin capabilities or to
1017 * issue miscellaneous "set" requests.
1018 *****************************************************************************/
1019 static int VCDControl( access_t *p_access, int i_query, va_list args )
1021 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1025 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1026 "query %d", i_query );
1030 /* Pass back a copy of meta information that was gathered when we
1031 during the Open/Initialize call.
1033 case ACCESS_GET_META:
1035 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1037 if( p_vcdplayer->p_meta )
1039 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg(args,vlc_meta_t**);
1041 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1042 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1046 msg_Warn( p_access, "tried to copy NULL meta info" );
1050 return VLC_EGENERIC;
1052 case ACCESS_CAN_SEEK:
1053 case ACCESS_CAN_FASTSEEK:
1054 case ACCESS_CAN_PAUSE:
1055 case ACCESS_CAN_CONTROL_PACE:
1057 bool *pb_bool = (bool*)va_arg( args, bool* );
1059 dbg_print( INPUT_DBG_EVENT,
1060 "seek/fastseek/pause/can_control_pace" );
1067 case ACCESS_GET_PTS_DELAY:
1069 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1070 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1071 * MILLISECONDS_PER_SEC;
1072 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1078 case ACCESS_SET_PAUSE_STATE:
1079 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1083 case ACCESS_GET_TITLE_INFO:
1085 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1086 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1087 input_title_t ***ppp_title
1088 = (input_title_t***)va_arg( args, input_title_t*** );
1089 char *psz_mrl = malloc( psz_mrl_max );
1092 pi_int = (int*)va_arg( args, int* );
1094 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1095 p_vcdplayer->i_titles );
1099 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1100 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1101 VCDMetaInfo( p_access, psz_mrl );
1105 /* Duplicate title info */
1106 if( p_vcdplayer->i_titles == 0 )
1108 *pi_int = 0; ppp_title = NULL;
1111 *pi_int = p_vcdplayer->i_titles;
1112 *ppp_title = malloc( sizeof( input_title_t **)
1113 * p_vcdplayer->i_titles );
1115 if (!*ppp_title) return VLC_ENOMEM;
1117 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1119 if ( p_vcdplayer->p_title[i] )
1121 vlc_input_title_Duplicate( p_vcdplayer->p_title[i] );
1126 case ACCESS_SET_TITLE:
1127 i = (int)va_arg( args, int );
1129 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1130 if( i != p_access->info.i_title )
1132 vcdinfo_itemid_t itemid;
1133 track_t i_track = i+1;
1134 unsigned int i_entry =
1135 vcdinfo_track_get_entry( p_vcdplayer->vcd, i_track);
1137 if( i < p_vcdplayer->i_tracks )
1139 /* FIXME! For now we are assuming titles are only
1140 tracks and that track == title+1 */
1141 itemid.num = i_track;
1142 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1146 /* FIXME! i_tracks+2 are Segments, but we need to
1147 be able to figure out which segment of that.
1148 i_tracks+1 is either Segments (if no LIDs) or
1149 LIDs otherwise. Again need a way to get the LID
1152 "Trying to set track (%u) beyond end of last track (%u).",
1153 i+1, p_vcdplayer->i_tracks );
1154 return VLC_EGENERIC;
1157 VCDSetOrigin(p_access,
1158 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry),
1163 case ACCESS_SET_SEEKPOINT:
1165 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1166 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1168 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1169 if( t->i_seekpoint > 0 )
1171 track_t i_track = p_access->info.i_title+1;
1174 /* FIXME! For now we are assuming titles are only
1175 tracks and that track == title+1 and we the play
1176 item is entries (not tracks or lids).
1177 We need to generalize all of this.
1180 if (i < p_vcdplayer->i_entries)
1182 p_vcdplayer->play_item.num = i;
1183 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1184 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1185 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1187 p_vcdplayer->play_item.num = i
1188 = i - p_vcdplayer->i_entries;
1189 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1193 p_vcdplayer->play_item.num = i
1194 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1195 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1196 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1199 VCDSetOrigin( p_access,
1200 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i),
1201 i_track, &(p_vcdplayer->play_item) );
1206 case ACCESS_SET_PRIVATE_ID_STATE:
1207 dbg_print( INPUT_DBG_EVENT, "set private id" );
1208 return VLC_EGENERIC;
1211 msg_Warn( p_access, "unimplemented query in control" );
1212 return VLC_EGENERIC;