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>>
37 #include <cdio/cdio.h>
38 #include <cdio/cd_types.h>
39 #include <cdio/logging.h>
40 #include <cdio/util.h>
41 #include <libvcd/info.h>
42 #include <libvcd/logging.h>
47 extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
48 const vcdinfo_itemid_t *p_itemid );
50 /*****************************************************************************
52 *****************************************************************************/
54 /* First those which are accessed from outside (via pointers). */
55 static block_t *VCDReadBlock ( access_t * );
57 static int VCDControl ( access_t *p_access, int i_query,
60 /* Now those which are strictly internal */
61 static vlc_bool_t VCDEntryPoints ( access_t * );
62 static vlc_bool_t VCDLIDs ( access_t * );
63 static vlc_bool_t VCDSegments ( access_t * );
64 static int VCDTitles ( access_t * );
65 static char *VCDParse ( access_t *,
66 /*out*/ vcdinfo_itemid_t * p_itemid ,
67 /*out*/ vlc_bool_t *play_single_item );
69 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
70 const char *p_varname, char *p_label,
71 const char *p_debug_label );
73 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
75 /****************************************************************************
77 ****************************************************************************/
79 /* FIXME: This variable is a hack. Would be nice to eliminate the
82 static access_t *p_vcd_access = NULL;
84 /* process messages that originate from libcdio. */
86 cdio_log_handler (cdio_log_level_t level, const char message[])
88 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
92 if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
93 msg_Dbg( p_vcd_access, message);
96 msg_Warn( p_vcd_access, message);
100 msg_Err( p_vcd_access, message);
103 msg_Warn( p_vcd_access, message,
104 _("The above message had unknown log level"),
110 /* process messages that originate from vcdinfo. */
112 vcd_log_handler (vcd_log_level_t level, const char message[])
114 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
118 if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
119 msg_Dbg( p_vcd_access, message);
122 msg_Warn( p_vcd_access, message);
126 msg_Err( p_vcd_access, message);
129 msg_Warn( p_vcd_access, "%s\n%s %d", message,
130 _("The above message had unknown vcdimager log level"),
136 /*****************************************************************************
137 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
138 NULL is returned if something went wrong.
139 *****************************************************************************/
141 VCDReadBlock( access_t * p_access )
143 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
144 const int i_blocks = p_vcdplayer->i_blocks_per_read;
151 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
152 (long unsigned int) p_vcdplayer->i_lsn );
154 /* Allocate a block for the reading */
155 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
157 msg_Err( p_access, "cannot get a new block of size: %i",
158 i_blocks * M2F2_SECTOR_SIZE );
159 block_Release( p_block );
163 p_buf = (uint8_t *) p_block->p_buffer;
164 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
166 vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
168 p_access->info.i_pos += M2F2_SECTOR_SIZE;
170 switch ( read_status ) {
172 /* End reached. Return NULL to indicated this. */
173 /* We also set the postion to the end so the higher level
174 (demux?) doesn't try to keep reading. If everything works out
175 right this shouldn't have to happen.
178 if ( p_access->info.i_pos != p_access->info.i_size ) {
180 "At end but pos (%llu) is not size (%llu). Adjusting.",
181 p_access->info.i_pos, p_access->info.i_size );
182 p_access->info.i_pos = p_access->info.i_size;
186 block_Release( p_block );
190 /* Some sort of error. Should we increment lsn? to skip block?
192 block_Release( p_block );
194 case READ_STILL_FRAME:
196 /* FIXME The below should be done in an event thread.
200 msleep( MILLISECONDS_PER_SEC * *p_buf );
201 VCDSetOrigin(p_access, p_vcdplayer->origin_lsn, p_vcdplayer->i_track,
202 &(p_vcdplayer->play_item));
203 // p_vcd->in_still = VLC_FALSE;
204 dbg_print(INPUT_DBG_STILL, "still wait time done");
206 vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);
209 block_Release( p_block );
219 p_buf += M2F2_SECTOR_SIZE;
220 /* Update seekpoint */
221 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
223 unsigned int i_entry = p_vcdplayer->play_item.num+1;
224 lsn_t i_lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
225 if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
227 const track_t i_track = p_vcdplayer->i_track;
229 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
230 "entry change to %d, current LSN %u >= end %u",
231 i_entry, p_vcdplayer->i_lsn, i_lsn);
233 p_vcdplayer->play_item.num = i_entry;
235 VCDSetOrigin( p_access, i_lsn, i_track,
236 &(p_vcdplayer->play_item) );
245 /****************************************************************************
247 ****************************************************************************/
249 VCDSeek( access_t * p_access, int64_t i_pos )
251 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
254 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
255 const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
256 unsigned int i_entry = VCDINFO_INVALID_ENTRY;
259 /* Next sector to read */
260 p_access->info.i_pos = i_pos;
261 p_vcdplayer->i_lsn = (i_pos / (int64_t) M2F2_SECTOR_SIZE) +
262 p_vcdplayer->origin_lsn;
264 switch (p_vcdplayer->play_item.type) {
265 case VCDINFO_ITEM_TYPE_TRACK:
266 case VCDINFO_ITEM_TYPE_ENTRY:
269 p_vcdplayer->b_valid_ep = VLC_FALSE;
273 if( p_vcdplayer->b_valid_ep )
275 for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
277 if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
279 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
280 "chapter", _("Entry"), "Setting entry" );
286 vcdinfo_itemid_t itemid;
287 itemid.num = i_entry;
288 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
289 VCDSetOrigin(p_access, p_vcdplayer->i_lsn, p_vcdplayer->i_track,
294 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
295 "orig %lu, cur: %lu, offset: %lld, entry %d",
296 (long unsigned int) p_vcdplayer->origin_lsn,
297 (long unsigned int) p_vcdplayer->i_lsn, i_pos,
301 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
303 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
304 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
307 /* Update current seekpoint */
308 if( i_seekpoint != p_access->info.i_seekpoint )
310 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
311 (long unsigned int) i_seekpoint );
312 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
313 p_access->info.i_seekpoint = i_seekpoint;
317 p_access->info.b_eof = VLC_FALSE;
322 /*****************************************************************************
323 VCDEntryPoints: Reads the information about the entry points on the disc
324 and initializes area information with that.
325 Before calling this track information should have been read in.
326 *****************************************************************************/
328 VCDEntryPoints( access_t * p_access )
330 if (!p_access || !p_access->p_sys) return VLC_FALSE;
333 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
334 const unsigned int i_entries =
335 vcdinfo_get_num_entries(p_vcdplayer->vcd);
336 const track_t i_last_track
337 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
338 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
341 if (0 == i_entries) {
342 LOG_ERR ("no entires found -- something is wrong" );
346 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
348 if( p_vcdplayer->p_entries == NULL )
350 LOG_ERR ("not enough memory for entry points treatment" );
354 p_vcdplayer->i_entries = i_entries;
356 for( i = 0 ; i < i_entries ; i++ )
358 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
359 if( i_track <= i_last_track ) {
360 seekpoint_t *s = vlc_seekpoint_New();
363 snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i );
365 p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
367 s->psz_name = strdup(psz_entry);
369 (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track))
372 dbg_print( INPUT_DBG_MRL,
373 "%s, lsn %d, byte_offset %ld",
374 s->psz_name, p_vcdplayer->p_entries[i],
375 (unsigned long int) s->i_byte_offset);
376 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
377 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
380 msg_Warn( p_access, "wrong track number found in entry points" );
382 p_vcdplayer->b_valid_ep = VLC_TRUE;
387 /*****************************************************************************
388 * VCDSegments: Reads the information about the segments the disc.
389 *****************************************************************************/
391 VCDSegments( access_t * p_access )
393 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
397 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
399 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
400 "Segments: %d", p_vcdplayer->i_segments);
402 if ( 0 == p_vcdplayer->i_segments ) return VLC_FALSE;
404 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
405 p_vcdplayer->i_titles++;
407 t->i_size = 0; /* Not sure Segments have a size associated */
408 t->psz_name = strdup(_("Segments"));
410 /* We have one additional segment allocated so we can get the size
411 by subtracting seg[i+1] - seg[i].
413 p_vcdplayer->p_segments =
414 malloc( sizeof( lsn_t ) * (p_vcdplayer->i_segments+1) );
415 if( p_vcdplayer->p_segments == NULL )
417 LOG_ERR ("not enough memory for segment treatment" );
421 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
423 char psz_segment[100];
424 seekpoint_t *s = vlc_seekpoint_New();
425 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
427 snprintf( psz_segment, sizeof(psz_segment), "%s %02d", _("Segment"),
430 s->i_byte_offset = 0; /* Not sure what this would mean here */
431 s->psz_name = strdup(psz_segment);
432 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
435 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
436 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
437 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
438 p_vcdplayer->i_segments-1);
443 /*****************************************************************************
444 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
446 We start area addressing for tracks at 1 since the default area 0
447 is reserved for segments.
448 *****************************************************************************/
450 VCDTitles( access_t * p_access )
452 /* We'll assume a VCD has its first MPEG track
453 cdio_get_first_track_num()+1 could be used if one wanted to be
454 very careful about this. Note: cdio_get_first_track() will give the
455 ISO-9660 track before the MPEG tracks.
458 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
461 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
464 p_vcdplayer->i_titles = 0;
465 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
467 input_title_t *t = p_vcdplayer->p_title[i-1] =
468 vlc_input_title_New();
471 snprintf( psz_track, sizeof(psz_track), "%s %02d", _("Track"),
473 t->i_size = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
475 * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
476 t->psz_name = strdup(psz_track);
478 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld", i, t->i_size );
480 p_vcdplayer->i_titles++;
487 /*****************************************************************************
488 VCDLIDs: Reads the LIST IDs from the LOT.
489 *****************************************************************************/
491 VCDLIDs( access_t * p_access )
493 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
495 unsigned int i_lid, i_title;
497 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
498 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
500 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
501 "LIDs: %d", p_vcdplayer->i_lids);
503 if ( 0 == p_vcdplayer->i_lids ) return VLC_FALSE;
505 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
507 vcdinfo_visit_lot (p_vcdplayer->vcd, false);
511 We need to change libvcdinfo to be more robust when there are
512 problems reading the extended PSD. Given that area-highlighting and
513 selection features in the extended PSD haven't been implemented,
514 it's best then to not try to read this at all.
516 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
517 vcdinfo_visit_lot (p_vcdplayer->vcd, VLC_TRUE);
521 /* Set up LIDs Navigation Menu */
522 t = vlc_input_title_New();
523 t->b_menu = VLC_TRUE;
524 t->psz_name = strdup( "LIDs" );
526 i_title = p_vcdplayer->i_tracks;
527 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
530 seekpoint_t *s = vlc_seekpoint_New();
532 snprintf( psz_lid, sizeof(psz_lid), "%s %02d", _("LID"),
535 s->i_byte_offset = 0; /* A lid doesn't have an offset
536 size associated with it */
537 s->psz_name = strdup(psz_lid);
538 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
541 #if DYNAMICALLY_ALLOCATED
542 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
544 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
545 p_vcdplayer->i_titles++;
551 /*****************************************************************************
552 * VCDParse: parse command line
553 *****************************************************************************/
555 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
556 /*out*/ vlc_bool_t *play_single_item )
558 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
563 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
564 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
566 *play_single_item = VLC_FALSE;
570 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
575 /* On Win32 we want the VCD access plugin to be explicitly requested,
576 * we end up with lots of problems otherwise */
577 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
580 if( !p_access->psz_path )
585 psz_parser = psz_source = strdup( p_access->psz_path );
587 /* Parse input string :
588 * [device][@[type][title]] */
589 while( *psz_parser && *psz_parser != '@' )
594 if( *psz_parser == '@' )
596 /* Found the divide between the source name and the
597 type+entry number. */
604 switch(*psz_parser) {
606 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
608 *play_single_item = VLC_TRUE;
611 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
613 *play_single_item = VLC_FALSE;
616 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
618 *play_single_item = VLC_TRUE;
621 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
623 *play_single_item = VLC_TRUE;
629 num = strtol( psz_parser, &psz_next, 10 );
630 if ( *psz_parser != '\0' && *psz_next == '\0')
636 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
642 /* No source specified, so figure it out. */
643 if( !p_access->psz_access ) return NULL;
645 psz_source = config_GetPsz( p_access, "vcd" );
647 if( !psz_source || 0==strlen(psz_source) ) {
648 /* Scan for a CD-ROM drive with a VCD in it. */
649 char **cd_drives = cdio_get_devices_with_cap( NULL,
650 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
651 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
653 if( NULL == cd_drives ) return NULL;
654 if( cd_drives[0] == NULL )
656 cdio_free_device_list( cd_drives );
659 psz_source = strdup( cd_drives[0] );
660 cdio_free_device_list( cd_drives );
664 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
665 "source=%s entry=%d type=%d",
666 psz_source, p_itemid->num, p_itemid->type);
672 Sets start origin for subsequent seeks/reads
675 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
676 const vcdinfo_itemid_t *p_itemid )
678 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
680 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
681 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
684 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
686 switch (p_vcdplayer->play_item.type) {
687 case VCDINFO_ITEM_TYPE_ENTRY:
688 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
689 "chapter", _("Entry"), "Setting entry/segment");
690 p_access->info.i_title = i_track-1;
691 if (p_vcdplayer->b_track_length)
693 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
694 p_access->info.i_pos = (int64_t) M2F2_SECTOR_SIZE *
695 (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track) - i_lsn) ;
697 p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
698 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd, p_itemid->num);
699 p_access->info.i_pos = 0;
701 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %llu, pos: %llu",
702 p_access->info.i_size, p_access->info.i_pos );
703 p_access->info.i_seekpoint = p_itemid->num;
706 case VCDINFO_ITEM_TYPE_SEGMENT:
707 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
708 "chapter", _("Segment"), "Setting entry/segment");
709 /* The last title entry is the for segments (when segments exist
710 and they must here. The segment seekpoints are stored after
711 the entry seekpoints and (zeroed) lid seekpoints.
713 p_access->info.i_title = p_vcdplayer->i_titles - 1;
714 p_access->info.i_size = 0; /* No seeking on stills, please. */
715 p_access->info.i_pos = 0;
716 p_access->info.i_seekpoint = p_vcdplayer->i_entries
717 + p_vcdplayer->i_lids + p_itemid->num;
720 case VCDINFO_ITEM_TYPE_TRACK:
721 p_access->info.i_title = i_track-1;
722 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
723 p_access->info.i_pos = 0;
724 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
729 msg_Warn( p_access, "can't set origin for play type %d",
730 p_vcdplayer->play_item.type );
733 p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
734 | INPUT_UPDATE_SEEKPOINT;
736 VCDUpdateTitle( p_access );
740 /*****************************************************************************
741 * vcd_Open: Opens a VCD device or file initializes, a list of
742 tracks, segements and entry lsns and sizes and returns an opaque handle.
743 *****************************************************************************/
744 static vcdinfo_obj_t *
745 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
747 access_t *p_access = (access_t *)p_this;
748 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
749 vcdinfo_obj_t *p_vcdobj;
753 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
755 if( !psz_dev ) return NULL;
757 actual_dev=strdup(psz_dev);
758 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
766 Save summary info on tracks, segments and entries...
769 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
770 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
771 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
773 for (i=0; i<p_vcdplayer->i_tracks; i++) {
774 unsigned int track_num=i+1;
775 p_vcdplayer->track[i].size =
776 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
777 p_vcdplayer->track[i].start_LSN =
778 vcdinfo_get_track_lsn(p_vcdobj, track_num);
781 p_vcdplayer->track = NULL;
783 if ( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
784 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
785 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
787 for (i=0; i<p_vcdplayer->i_entries; i++) {
788 p_vcdplayer->entry[i].size =
789 vcdinfo_get_entry_sect_count(p_vcdobj, i);
790 p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lsn(p_vcdobj, i);
793 p_vcdplayer->entry = NULL;
795 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
796 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
797 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
799 for (i=0; i<p_vcdplayer->i_segments; i++) {
800 p_vcdplayer->segment[i].size =
801 vcdinfo_get_seg_sector_count(p_vcdobj, i);
802 p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
805 p_vcdplayer->segment = NULL;
810 /****************************************************************************
811 Update the "varname" variable to i_num without triggering a callback.
812 ****************************************************************************/
814 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
815 const char *p_varname, char *p_label,
816 const char *p_debug_label)
821 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
822 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
826 text.psz_string = p_label;
827 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
829 var_Change( p_access, p_varname, i_action, &val, NULL );
833 /*****************************************************************************
835 *****************************************************************************/
837 /*****************************************************************************
839 read in meta-information about VCD: the number of tracks, segments,
840 entries, size and starting information. Then set up state variables so
841 that we read/seek starting at the location specified.
843 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
844 and VLC_EGENERIC for some other error.
845 *****************************************************************************/
847 VCDOpen ( vlc_object_t *p_this )
849 access_t *p_access = (access_t *)p_this;
850 vcdplayer_t *p_vcdplayer;
852 vcdinfo_itemid_t itemid;
853 vlc_bool_t play_single_item = VLC_FALSE;
855 p_access->pf_read = NULL;
856 p_access->pf_block = VCDReadBlock;
857 p_access->pf_control = VCDControl;
858 p_access->pf_seek = VCDSeek;
860 p_access->info.i_update = 0;
861 p_access->info.i_size = 0;
862 p_access->info.i_pos = 0;
863 p_access->info.b_eof = VLC_FALSE;
864 p_access->info.i_title = 0;
865 p_access->info.i_seekpoint = 0;
867 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
869 if( p_vcdplayer == NULL )
871 LOG_ERR ("out of memory" );
875 p_vcdplayer->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
876 p_access->p_sys = (access_sys_t *) p_vcdplayer;
878 /* Set where to log errors messages from libcdio. */
879 p_vcd_access = p_access;
880 cdio_log_set_handler ( cdio_log_handler );
881 vcd_log_set_handler ( vcd_log_handler );
883 psz_source = VCDParse( p_access, &itemid, &play_single_item );
885 if ( NULL == psz_source )
888 return( VLC_EGENERIC );
891 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
892 psz_source, p_access->psz_path );
894 p_vcdplayer->psz_source = strdup(psz_source);
895 p_vcdplayer->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
896 "-blocks-per-read" );
897 p_vcdplayer->b_track_length = config_GetInt( p_this, MODULE_STRING
899 p_vcdplayer->in_still = VLC_FALSE;
900 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
901 p_vcdplayer->p_input = vlc_object_find( p_access,
904 // p_vcdplayer->p_meta = vlc_meta_New();
905 p_vcdplayer->p_segments = NULL;
906 p_vcdplayer->p_entries = NULL;
910 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
915 p_vcdplayer->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcdplayer->vcd);;
917 /* Get track information. */
918 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
920 if( p_vcdplayer->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcdplayer->i_tracks ) {
921 vcdinfo_close( p_vcdplayer->vcd );
922 LOG_ERR ("no movie tracks found" );
926 /* Build Navigation Title table for the tracks. */
927 VCDTitles( p_access );
929 /* Add into the above entry points as "Chapters". */
930 if( ! VCDEntryPoints( p_access ) )
932 msg_Warn( p_access, "could not read entry points, will not use them" );
933 p_vcdplayer->b_valid_ep = VLC_FALSE;
936 /* Initialize LID info and add that as a menu item */
937 if( ! VCDLIDs( p_access ) )
939 msg_Warn( p_access, "could not read entry LIDs" );
942 /* Do we set PBC (via LID) on? */
944 ( VCDINFO_ITEM_TYPE_LID == itemid.type
945 && p_vcdplayer->i_lids > itemid.num )
947 : VCDINFO_INVALID_ENTRY;
949 /* Initialize segment information and add that a "Track". */
950 VCDSegments( p_access );
952 vcdplayer_play( p_access, itemid );
954 p_access->psz_demux = strdup( "ps" );
957 if (play_single_item)
958 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
963 p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
964 p_vcdplayer->p_intf->b_block = VLC_FALSE;
966 p_vcdplayer->p_access = p_access;
969 intf_RunThread( p_vcdplayer->p_intf );
976 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
982 /*****************************************************************************
983 * VCDClose: closes VCD releasing allocated memory.
984 *****************************************************************************/
986 VCDClose ( vlc_object_t *p_this )
988 access_t *p_access = (access_t *)p_this;
989 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
991 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
995 for (i=0 ; i<p_vcdplayer->i_titles; i++)
996 if (p_vcdplayer->p_title[i])
997 free(p_vcdplayer->p_title[i]->psz_name);
1000 vcdinfo_close( p_vcdplayer->vcd );
1002 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
1004 FREENULL( p_vcdplayer->p_entries );
1005 FREENULL( p_vcdplayer->p_segments );
1006 FREENULL( p_vcdplayer->psz_source );
1007 FREENULL( p_vcdplayer->track );
1008 FREENULL( p_vcdplayer->segment );
1009 FREENULL( p_vcdplayer->entry );
1010 FREENULL( p_access->psz_demux );
1011 FREENULL( p_vcdplayer );
1012 p_vcd_access = NULL;
1015 /*****************************************************************************
1016 * Control: The front-end or vlc engine calls here to ether get
1017 * information such as meta information or plugin capabilities or to
1018 * issue miscellaneous "set" requests.
1019 *****************************************************************************/
1020 static int VCDControl( access_t *p_access, int i_query, va_list args )
1022 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1026 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1027 "query %d", i_query );
1031 /* Pass back a copy of meta information that was gathered when we
1032 during the Open/Initialize call.
1034 case ACCESS_GET_META:
1036 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1038 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1040 if( p_vcdplayer->p_meta )
1042 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1043 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1047 msg_Warn( p_access, "tried to copy NULL meta info" );
1051 return VLC_EGENERIC;
1053 case ACCESS_CAN_SEEK:
1054 case ACCESS_CAN_FASTSEEK:
1055 case ACCESS_CAN_PAUSE:
1056 case ACCESS_CAN_CONTROL_PACE:
1058 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1060 dbg_print( INPUT_DBG_EVENT,
1061 "seek/fastseek/pause/can_control_pace" );
1062 *pb_bool = VLC_TRUE;
1068 case ACCESS_GET_MTU:
1069 pi_int = (int*)va_arg( args, int * );
1070 *pi_int = (p_vcdplayer->i_blocks_per_read * M2F2_SECTOR_SIZE);
1071 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1074 case ACCESS_GET_PTS_DELAY:
1076 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1077 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1078 * MILLISECONDS_PER_SEC;
1079 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1085 case ACCESS_SET_PAUSE_STATE:
1086 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1090 case ACCESS_GET_TITLE_INFO:
1092 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1093 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1094 input_title_t ***ppp_title
1095 = (input_title_t***)va_arg( args, input_title_t*** );
1096 char *psz_mrl = malloc( psz_mrl_max );
1099 pi_int = (int*)va_arg( args, int* );
1101 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1102 p_vcdplayer->i_titles );
1104 if( psz_mrl == NULL ) {
1105 msg_Warn( p_access, "out of memory" );
1107 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1108 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1109 VCDMetaInfo( p_access, psz_mrl );
1113 /* Duplicate title info */
1114 if( p_vcdplayer->i_titles == 0 )
1116 *pi_int = 0; ppp_title = NULL;
1119 *pi_int = p_vcdplayer->i_titles;
1120 *ppp_title = malloc( sizeof( input_title_t **)
1121 * p_vcdplayer->i_titles );
1123 if (!*ppp_title) return VLC_ENOMEM;
1125 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1127 if ( p_vcdplayer->p_title[i] )
1129 vlc_input_title_Duplicate( p_vcdplayer->p_title[i] );
1134 case ACCESS_SET_TITLE:
1135 i = (int)va_arg( args, int );
1137 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1138 if( i != p_access->info.i_title )
1140 vcdinfo_itemid_t itemid;
1141 track_t i_track = i+1;
1142 unsigned int i_entry =
1143 vcdinfo_track_get_entry( p_vcdplayer->vcd, i_track);
1145 if( i < p_vcdplayer->i_tracks )
1147 /* FIXME! For now we are assuming titles are only
1148 tracks and that track == title+1 */
1149 itemid.num = i_track;
1150 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1154 /* FIXME! i_tracks+2 are Segments, but we need to
1155 be able to figure out which segment of that.
1156 i_tracks+1 is either Segments (if no LIDs) or
1157 LIDs otherwise. Again need a way to get the LID
1160 "Trying to set track (%u) beyond end of last track (%u).",
1161 i+1, p_vcdplayer->i_tracks );
1162 return VLC_EGENERIC;
1165 VCDSetOrigin(p_access,
1166 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry),
1171 case ACCESS_SET_SEEKPOINT:
1173 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1174 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1176 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1177 if( t->i_seekpoint > 0 )
1179 track_t i_track = p_access->info.i_title+1;
1182 /* FIXME! For now we are assuming titles are only
1183 tracks and that track == title+1 and we the play
1184 item is entries (not tracks or lids).
1185 We need to generalize all of this.
1188 if (i < p_vcdplayer->i_entries)
1190 p_vcdplayer->play_item.num = i;
1191 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1192 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1193 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1195 p_vcdplayer->play_item.num = i
1196 = i - p_vcdplayer->i_entries;
1197 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1201 p_vcdplayer->play_item.num = i
1202 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1203 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1204 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1207 VCDSetOrigin( p_access,
1208 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i),
1209 i_track, &(p_vcdplayer->play_item) );
1214 case ACCESS_SET_PRIVATE_ID_STATE:
1215 dbg_print( INPUT_DBG_EVENT, "set private id" );
1216 return VLC_EGENERIC;
1219 msg_Warn( p_access, "unimplemented query in control" );
1220 return VLC_EGENERIC;