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 *****************************************************************************/
33 #include <vlc_interface.h>
34 #include <vlc_input.h>
35 #include <vlc_access.h>
38 #include <cdio/cdio.h>
39 #include <cdio/cd_types.h>
40 #include <cdio/logging.h>
41 #include <cdio/util.h>
42 #include <libvcd/info.h>
43 #include <libvcd/logging.h>
48 extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
49 const vcdinfo_itemid_t *p_itemid );
51 /*****************************************************************************
53 *****************************************************************************/
55 /* First those which are accessed from outside (via pointers). */
56 static block_t *VCDReadBlock ( access_t * );
58 static int VCDControl ( access_t *p_access, int i_query,
61 /* Now those which are strictly internal */
62 static vlc_bool_t VCDEntryPoints ( access_t * );
63 static vlc_bool_t VCDLIDs ( access_t * );
64 static vlc_bool_t VCDSegments ( access_t * );
65 static int VCDTitles ( access_t * );
66 static char *VCDParse ( access_t *,
67 /*out*/ vcdinfo_itemid_t * p_itemid ,
68 /*out*/ vlc_bool_t *play_single_item );
70 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
71 const char *p_varname, char *p_label,
72 const char *p_debug_label );
74 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
76 /****************************************************************************
78 ****************************************************************************/
80 /* FIXME: This variable is a hack. Would be nice to eliminate the
83 static access_t *p_vcd_access = NULL;
85 /* process messages that originate from libcdio. */
87 cdio_log_handler (cdio_log_level_t level, const char message[])
89 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
93 if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
94 msg_Dbg( p_vcd_access, "%s", message);
97 msg_Warn( p_vcd_access, "%s", message);
100 case CDIO_LOG_ASSERT:
101 msg_Err( p_vcd_access, "%s", message);
104 msg_Warn( p_vcd_access, "%s\n%s %d", message,
105 _("The above message had unknown log level"),
111 /* process messages that originate from vcdinfo. */
113 vcd_log_handler (vcd_log_level_t level, const char message[])
115 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
119 if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
120 msg_Dbg( p_vcd_access, "%s", message);
123 msg_Warn( p_vcd_access, "%s", message);
127 msg_Err( p_vcd_access, "%s", message);
130 msg_Warn( p_vcd_access, "%s\n%s %d", message,
131 _("The above message had unknown vcdimager log level"),
137 /*****************************************************************************
138 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
139 NULL is returned if something went wrong.
140 *****************************************************************************/
142 VCDReadBlock( access_t * p_access )
144 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
145 const int i_blocks = p_vcdplayer->i_blocks_per_read;
152 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
153 (long unsigned int) p_vcdplayer->i_lsn );
155 /* Allocate a block for the reading */
156 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
158 msg_Err( p_access, "cannot get a new block of size: %i",
159 i_blocks * M2F2_SECTOR_SIZE );
160 block_Release( p_block );
164 p_buf = (uint8_t *) p_block->p_buffer;
165 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
167 vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
169 p_access->info.i_pos += M2F2_SECTOR_SIZE;
171 switch ( read_status ) {
173 /* End reached. Return NULL to indicated this. */
174 /* We also set the postion to the end so the higher level
175 (demux?) doesn't try to keep reading. If everything works out
176 right this shouldn't have to happen.
179 if ( p_access->info.i_pos != p_access->info.i_size ) {
181 "At end but pos (%llu) is not size (%llu). Adjusting.",
182 p_access->info.i_pos, p_access->info.i_size );
183 p_access->info.i_pos = p_access->info.i_size;
187 block_Release( p_block );
191 /* Some sort of error. Should we increment lsn? to skip block?
193 block_Release( p_block );
195 case READ_STILL_FRAME:
197 /* FIXME The below should be done in an event thread.
201 msleep( MILLISECONDS_PER_SEC * *p_buf );
202 VCDSetOrigin(p_access, p_vcdplayer->origin_lsn, p_vcdplayer->i_track,
203 &(p_vcdplayer->play_item));
204 // p_vcd->in_still = VLC_FALSE;
205 dbg_print(INPUT_DBG_STILL, "still wait time done");
207 vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);
210 block_Release( p_block );
220 p_buf += M2F2_SECTOR_SIZE;
221 /* Update seekpoint */
222 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
224 unsigned int i_entry = p_vcdplayer->play_item.num+1;
225 lsn_t i_lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
226 if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
228 const track_t i_track = p_vcdplayer->i_track;
230 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
231 "entry change to %d, current LSN %u >= end %u",
232 i_entry, p_vcdplayer->i_lsn, i_lsn);
234 p_vcdplayer->play_item.num = i_entry;
236 VCDSetOrigin( p_access, i_lsn, i_track,
237 &(p_vcdplayer->play_item) );
246 /****************************************************************************
248 ****************************************************************************/
250 VCDSeek( access_t * p_access, int64_t i_pos )
252 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
255 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
256 const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
257 unsigned int i_entry = VCDINFO_INVALID_ENTRY;
260 /* Next sector to read */
261 p_access->info.i_pos = i_pos;
262 p_vcdplayer->i_lsn = (i_pos / (int64_t) M2F2_SECTOR_SIZE) +
263 p_vcdplayer->origin_lsn;
265 switch (p_vcdplayer->play_item.type) {
266 case VCDINFO_ITEM_TYPE_TRACK:
267 case VCDINFO_ITEM_TYPE_ENTRY:
270 p_vcdplayer->b_valid_ep = VLC_FALSE;
274 if( p_vcdplayer->b_valid_ep )
276 for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
278 if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
280 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
281 "chapter", _("Entry"), "Setting entry" );
287 vcdinfo_itemid_t itemid;
288 itemid.num = i_entry;
289 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
290 VCDSetOrigin(p_access, p_vcdplayer->i_lsn, p_vcdplayer->i_track,
295 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
296 "orig %lu, cur: %lu, offset: %lld, entry %d",
297 (long unsigned int) p_vcdplayer->origin_lsn,
298 (long unsigned int) p_vcdplayer->i_lsn, i_pos,
302 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
304 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
305 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
308 /* Update current seekpoint */
309 if( i_seekpoint != p_access->info.i_seekpoint )
311 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
312 (long unsigned int) i_seekpoint );
313 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
314 p_access->info.i_seekpoint = i_seekpoint;
318 p_access->info.b_eof = VLC_FALSE;
323 /*****************************************************************************
324 VCDEntryPoints: Reads the information about the entry points on the disc
325 and initializes area information with that.
326 Before calling this track information should have been read in.
327 *****************************************************************************/
329 VCDEntryPoints( access_t * p_access )
331 if (!p_access || !p_access->p_sys) return VLC_FALSE;
334 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
335 const unsigned int i_entries =
336 vcdinfo_get_num_entries(p_vcdplayer->vcd);
337 const track_t i_last_track
338 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
339 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
342 if (0 == i_entries) {
343 LOG_ERR ("no entires found -- something is wrong" );
347 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
349 if( p_vcdplayer->p_entries == NULL )
351 LOG_ERR ("not enough memory for entry points treatment" );
355 p_vcdplayer->i_entries = i_entries;
357 for( i = 0 ; i < i_entries ; i++ )
359 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
360 if( i_track <= i_last_track ) {
361 seekpoint_t *s = vlc_seekpoint_New();
364 snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i );
366 p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
368 s->psz_name = strdup(psz_entry);
370 (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track))
373 dbg_print( INPUT_DBG_MRL,
374 "%s, lsn %d, byte_offset %ld",
375 s->psz_name, p_vcdplayer->p_entries[i],
376 (unsigned long int) s->i_byte_offset);
377 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
378 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
381 msg_Warn( p_access, "wrong track number found in entry points" );
383 p_vcdplayer->b_valid_ep = VLC_TRUE;
388 /*****************************************************************************
389 * VCDSegments: Reads the information about the segments the disc.
390 *****************************************************************************/
392 VCDSegments( access_t * p_access )
394 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
398 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
400 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
401 "Segments: %d", p_vcdplayer->i_segments);
403 if ( 0 == p_vcdplayer->i_segments ) return VLC_FALSE;
405 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
406 p_vcdplayer->i_titles++;
408 t->i_size = 0; /* Not sure Segments have a size associated */
409 t->psz_name = strdup(_("Segments"));
411 /* We have one additional segment allocated so we can get the size
412 by subtracting seg[i+1] - seg[i].
414 p_vcdplayer->p_segments =
415 malloc( sizeof( lsn_t ) * (p_vcdplayer->i_segments+1) );
416 if( p_vcdplayer->p_segments == NULL )
418 LOG_ERR ("not enough memory for segment treatment" );
422 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
424 char psz_segment[100];
425 seekpoint_t *s = vlc_seekpoint_New();
426 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
428 snprintf( psz_segment, sizeof(psz_segment), "%s %02d", _("Segment"),
431 s->i_byte_offset = 0; /* Not sure what this would mean here */
432 s->psz_name = strdup(psz_segment);
433 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
436 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
437 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
438 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
439 p_vcdplayer->i_segments-1);
444 /*****************************************************************************
445 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
447 We start area addressing for tracks at 1 since the default area 0
448 is reserved for segments.
449 *****************************************************************************/
451 VCDTitles( access_t * p_access )
453 /* We'll assume a VCD has its first MPEG track
454 cdio_get_first_track_num()+1 could be used if one wanted to be
455 very careful about this. Note: cdio_get_first_track() will give the
456 ISO-9660 track before the MPEG tracks.
459 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
462 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
465 p_vcdplayer->i_titles = 0;
466 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
468 input_title_t *t = p_vcdplayer->p_title[i-1] =
469 vlc_input_title_New();
472 snprintf( psz_track, sizeof(psz_track), "%s %02d", _("Track"),
474 t->i_size = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
476 * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
477 t->psz_name = strdup(psz_track);
479 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld", i, t->i_size );
481 p_vcdplayer->i_titles++;
488 /*****************************************************************************
489 VCDLIDs: Reads the LIST IDs from the LOT.
490 *****************************************************************************/
492 VCDLIDs( access_t * p_access )
494 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
496 unsigned int i_lid, i_title;
498 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
499 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
501 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
502 "LIDs: %d", p_vcdplayer->i_lids);
504 if ( 0 == p_vcdplayer->i_lids ) return VLC_FALSE;
506 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
508 vcdinfo_visit_lot (p_vcdplayer->vcd, false);
512 We need to change libvcdinfo to be more robust when there are
513 problems reading the extended PSD. Given that area-highlighting and
514 selection features in the extended PSD haven't been implemented,
515 it's best then to not try to read this at all.
517 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
518 vcdinfo_visit_lot (p_vcdplayer->vcd, VLC_TRUE);
522 /* Set up LIDs Navigation Menu */
523 t = vlc_input_title_New();
524 t->b_menu = VLC_TRUE;
525 t->psz_name = strdup( "LIDs" );
527 i_title = p_vcdplayer->i_tracks;
528 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
531 seekpoint_t *s = vlc_seekpoint_New();
533 snprintf( psz_lid, sizeof(psz_lid), "%s %02d", _("LID"),
536 s->i_byte_offset = 0; /* A lid doesn't have an offset
537 size associated with it */
538 s->psz_name = strdup(psz_lid);
539 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
542 #if DYNAMICALLY_ALLOCATED
543 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
545 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
546 p_vcdplayer->i_titles++;
552 /*****************************************************************************
553 * VCDParse: parse command line
554 *****************************************************************************/
556 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
557 /*out*/ vlc_bool_t *play_single_item )
559 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
564 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
565 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
567 *play_single_item = VLC_FALSE;
571 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
576 /* On Win32 we want the VCD access plugin to be explicitly requested,
577 * we end up with lots of problems otherwise */
578 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
581 if( !p_access->psz_path )
586 psz_parser = psz_source = strdup( p_access->psz_path );
588 /* Parse input string :
589 * [device][@[type][title]] */
590 while( *psz_parser && *psz_parser != '@' )
595 if( *psz_parser == '@' )
597 /* Found the divide between the source name and the
598 type+entry number. */
605 switch(*psz_parser) {
607 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
609 *play_single_item = VLC_TRUE;
612 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
614 *play_single_item = VLC_FALSE;
617 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
619 *play_single_item = VLC_TRUE;
622 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
624 *play_single_item = VLC_TRUE;
630 num = strtol( psz_parser, &psz_next, 10 );
631 if ( *psz_parser != '\0' && *psz_next == '\0')
637 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
643 /* No source specified, so figure it out. */
644 if( !p_access->psz_access ) return NULL;
646 psz_source = config_GetPsz( p_access, "vcd" );
648 if( !psz_source || 0==strlen(psz_source) ) {
649 /* Scan for a CD-ROM drive with a VCD in it. */
650 char **cd_drives = cdio_get_devices_with_cap( NULL,
651 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
652 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
654 if( NULL == cd_drives ) return NULL;
655 if( cd_drives[0] == NULL )
657 cdio_free_device_list( cd_drives );
660 psz_source = strdup( cd_drives[0] );
661 cdio_free_device_list( cd_drives );
665 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
666 "source=%s entry=%d type=%d",
667 psz_source, p_itemid->num, p_itemid->type);
673 Sets start origin for subsequent seeks/reads
676 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
677 const vcdinfo_itemid_t *p_itemid )
679 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
681 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
682 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
685 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
687 switch (p_vcdplayer->play_item.type) {
688 case VCDINFO_ITEM_TYPE_ENTRY:
689 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
690 "chapter", _("Entry"), "Setting entry/segment");
691 p_access->info.i_title = i_track-1;
692 if (p_vcdplayer->b_track_length)
694 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
695 p_access->info.i_pos = (int64_t) M2F2_SECTOR_SIZE *
696 (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track) - i_lsn) ;
698 p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
699 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd, p_itemid->num);
700 p_access->info.i_pos = 0;
702 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %llu, pos: %llu",
703 p_access->info.i_size, p_access->info.i_pos );
704 p_access->info.i_seekpoint = p_itemid->num;
707 case VCDINFO_ITEM_TYPE_SEGMENT:
708 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
709 "chapter", _("Segment"), "Setting entry/segment");
710 /* The last title entry is the for segments (when segments exist
711 and they must here. The segment seekpoints are stored after
712 the entry seekpoints and (zeroed) lid seekpoints.
714 p_access->info.i_title = p_vcdplayer->i_titles - 1;
715 p_access->info.i_size = 0; /* No seeking on stills, please. */
716 p_access->info.i_pos = 0;
717 p_access->info.i_seekpoint = p_vcdplayer->i_entries
718 + p_vcdplayer->i_lids + p_itemid->num;
721 case VCDINFO_ITEM_TYPE_TRACK:
722 p_access->info.i_title = i_track-1;
723 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
724 p_access->info.i_pos = 0;
725 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
730 msg_Warn( p_access, "can't set origin for play type %d",
731 p_vcdplayer->play_item.type );
734 p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
735 | INPUT_UPDATE_SEEKPOINT;
737 VCDUpdateTitle( p_access );
741 /*****************************************************************************
742 * vcd_Open: Opens a VCD device or file initializes, a list of
743 tracks, segements and entry lsns and sizes and returns an opaque handle.
744 *****************************************************************************/
745 static vcdinfo_obj_t *
746 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
748 access_t *p_access = (access_t *)p_this;
749 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
750 vcdinfo_obj_t *p_vcdobj;
754 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
756 if( !psz_dev ) return NULL;
758 actual_dev=strdup(psz_dev);
759 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
767 Save summary info on tracks, segments and entries...
770 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
771 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
772 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
774 for (i=0; i<p_vcdplayer->i_tracks; i++) {
775 unsigned int track_num=i+1;
776 p_vcdplayer->track[i].size =
777 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
778 p_vcdplayer->track[i].start_LSN =
779 vcdinfo_get_track_lsn(p_vcdobj, track_num);
782 p_vcdplayer->track = NULL;
784 if ( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
785 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
786 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
788 for (i=0; i<p_vcdplayer->i_entries; i++) {
789 p_vcdplayer->entry[i].size =
790 vcdinfo_get_entry_sect_count(p_vcdobj, i);
791 p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lsn(p_vcdobj, i);
794 p_vcdplayer->entry = NULL;
796 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
797 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
798 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
800 for (i=0; i<p_vcdplayer->i_segments; i++) {
801 p_vcdplayer->segment[i].size =
802 vcdinfo_get_seg_sector_count(p_vcdobj, i);
803 p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
806 p_vcdplayer->segment = NULL;
811 /****************************************************************************
812 Update the "varname" variable to i_num without triggering a callback.
813 ****************************************************************************/
815 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
816 const char *p_varname, char *p_label,
817 const char *p_debug_label)
822 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
823 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
827 text.psz_string = p_label;
828 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
830 var_Change( p_access, p_varname, i_action, &val, NULL );
834 /*****************************************************************************
836 *****************************************************************************/
838 /*****************************************************************************
840 read in meta-information about VCD: the number of tracks, segments,
841 entries, size and starting information. Then set up state variables so
842 that we read/seek starting at the location specified.
844 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
845 and VLC_EGENERIC for some other error.
846 *****************************************************************************/
848 VCDOpen ( vlc_object_t *p_this )
850 access_t *p_access = (access_t *)p_this;
851 vcdplayer_t *p_vcdplayer;
853 vcdinfo_itemid_t itemid;
854 vlc_bool_t play_single_item = VLC_FALSE;
856 p_access->pf_read = NULL;
857 p_access->pf_block = VCDReadBlock;
858 p_access->pf_control = VCDControl;
859 p_access->pf_seek = VCDSeek;
861 p_access->info.i_update = 0;
862 p_access->info.i_size = 0;
863 p_access->info.i_pos = 0;
864 p_access->info.b_eof = VLC_FALSE;
865 p_access->info.i_title = 0;
866 p_access->info.i_seekpoint = 0;
868 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
870 if( p_vcdplayer == NULL )
872 LOG_ERR ("out of memory" );
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 = VLC_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= (vlc_bool_t) 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 = VLC_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 p_access->psz_demux = strdup( "ps" );
958 if (play_single_item)
959 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
964 p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
965 p_vcdplayer->p_intf->b_block = VLC_FALSE;
967 p_vcdplayer->p_access = p_access;
970 intf_RunThread( p_vcdplayer->p_intf );
977 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
983 /*****************************************************************************
984 * VCDClose: closes VCD releasing allocated memory.
985 *****************************************************************************/
987 VCDClose ( vlc_object_t *p_this )
989 access_t *p_access = (access_t *)p_this;
990 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
992 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
996 for (i=0 ; i<p_vcdplayer->i_titles; i++)
997 if (p_vcdplayer->p_title[i])
998 free(p_vcdplayer->p_title[i]->psz_name);
1001 vcdinfo_close( p_vcdplayer->vcd );
1003 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
1005 FREENULL( p_vcdplayer->p_entries );
1006 FREENULL( p_vcdplayer->p_segments );
1007 FREENULL( p_vcdplayer->psz_source );
1008 FREENULL( p_vcdplayer->track );
1009 FREENULL( p_vcdplayer->segment );
1010 FREENULL( p_vcdplayer->entry );
1011 FREENULL( p_access->psz_demux );
1012 FREENULL( p_vcdplayer );
1013 p_vcd_access = NULL;
1016 /*****************************************************************************
1017 * Control: The front-end or vlc engine calls here to ether get
1018 * information such as meta information or plugin capabilities or to
1019 * issue miscellaneous "set" requests.
1020 *****************************************************************************/
1021 static int VCDControl( access_t *p_access, int i_query, va_list args )
1023 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1027 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1028 "query %d", i_query );
1032 /* Pass back a copy of meta information that was gathered when we
1033 during the Open/Initialize call.
1035 case ACCESS_GET_META:
1037 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1039 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1041 if( p_vcdplayer->p_meta )
1043 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1044 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1048 msg_Warn( p_access, "tried to copy NULL meta info" );
1052 return VLC_EGENERIC;
1054 case ACCESS_CAN_SEEK:
1055 case ACCESS_CAN_FASTSEEK:
1056 case ACCESS_CAN_PAUSE:
1057 case ACCESS_CAN_CONTROL_PACE:
1059 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1061 dbg_print( INPUT_DBG_EVENT,
1062 "seek/fastseek/pause/can_control_pace" );
1063 *pb_bool = VLC_TRUE;
1069 case ACCESS_GET_MTU:
1070 pi_int = (int*)va_arg( args, int * );
1071 *pi_int = (p_vcdplayer->i_blocks_per_read * M2F2_SECTOR_SIZE);
1072 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1075 case ACCESS_GET_PTS_DELAY:
1077 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1078 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1079 * MILLISECONDS_PER_SEC;
1080 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1086 case ACCESS_SET_PAUSE_STATE:
1087 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1091 case ACCESS_GET_TITLE_INFO:
1093 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1094 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1095 input_title_t ***ppp_title
1096 = (input_title_t***)va_arg( args, input_title_t*** );
1097 char *psz_mrl = malloc( psz_mrl_max );
1100 pi_int = (int*)va_arg( args, int* );
1102 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1103 p_vcdplayer->i_titles );
1105 if( psz_mrl == NULL ) {
1106 msg_Warn( p_access, "out of memory" );
1108 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1109 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1110 VCDMetaInfo( p_access, psz_mrl );
1114 /* Duplicate title info */
1115 if( p_vcdplayer->i_titles == 0 )
1117 *pi_int = 0; ppp_title = NULL;
1120 *pi_int = p_vcdplayer->i_titles;
1121 *ppp_title = malloc( sizeof( input_title_t **)
1122 * p_vcdplayer->i_titles );
1124 if (!*ppp_title) return VLC_ENOMEM;
1126 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1128 if ( p_vcdplayer->p_title[i] )
1130 vlc_input_title_Duplicate( p_vcdplayer->p_title[i] );
1135 case ACCESS_SET_TITLE:
1136 i = (int)va_arg( args, int );
1138 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1139 if( i != p_access->info.i_title )
1141 vcdinfo_itemid_t itemid;
1142 track_t i_track = i+1;
1143 unsigned int i_entry =
1144 vcdinfo_track_get_entry( p_vcdplayer->vcd, i_track);
1146 if( i < p_vcdplayer->i_tracks )
1148 /* FIXME! For now we are assuming titles are only
1149 tracks and that track == title+1 */
1150 itemid.num = i_track;
1151 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1155 /* FIXME! i_tracks+2 are Segments, but we need to
1156 be able to figure out which segment of that.
1157 i_tracks+1 is either Segments (if no LIDs) or
1158 LIDs otherwise. Again need a way to get the LID
1161 "Trying to set track (%u) beyond end of last track (%u).",
1162 i+1, p_vcdplayer->i_tracks );
1163 return VLC_EGENERIC;
1166 VCDSetOrigin(p_access,
1167 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry),
1172 case ACCESS_SET_SEEKPOINT:
1174 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1175 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1177 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1178 if( t->i_seekpoint > 0 )
1180 track_t i_track = p_access->info.i_title+1;
1183 /* FIXME! For now we are assuming titles are only
1184 tracks and that track == title+1 and we the play
1185 item is entries (not tracks or lids).
1186 We need to generalize all of this.
1189 if (i < p_vcdplayer->i_entries)
1191 p_vcdplayer->play_item.num = i;
1192 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1193 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1194 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1196 p_vcdplayer->play_item.num = i
1197 = i - p_vcdplayer->i_entries;
1198 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1202 p_vcdplayer->play_item.num = i
1203 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1204 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1205 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1208 VCDSetOrigin( p_access,
1209 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i),
1210 i_track, &(p_vcdplayer->play_item) );
1215 case ACCESS_SET_PRIVATE_ID_STATE:
1216 dbg_print( INPUT_DBG_EVENT, "set private id" );
1217 return VLC_EGENERIC;
1220 msg_Warn( p_access, "unimplemented query in control" );
1221 return VLC_EGENERIC;