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 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
34 #include <vlc/input.h>
41 #include <cdio/cdio.h>
42 #include <cdio/cd_types.h>
43 #include <cdio/logging.h>
44 #include <cdio/util.h>
45 #include <libvcd/info.h>
46 #include <libvcd/logging.h>
48 #define FREE_AND_NULL(ptr) if (NULL != ptr) free(ptr); ptr = NULL;
50 extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
51 const vcdinfo_itemid_t *p_itemid );
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 vlc_bool_t VCDEntryPoints ( access_t * );
65 static vlc_bool_t VCDLIDs ( access_t * );
66 static vlc_bool_t VCDSegments ( access_t * );
67 static int VCDTitles ( access_t * );
68 static char *VCDParse ( access_t *,
69 /*out*/ vcdinfo_itemid_t * p_itemid ,
70 /*out*/ vlc_bool_t *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_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
95 if (p_vcd->i_debug & INPUT_DBG_CDIO)
96 msg_Dbg( p_vcd_access, message);
99 msg_Warn( p_vcd_access, message);
102 case CDIO_LOG_ASSERT:
103 msg_Err( p_vcd_access, message);
106 msg_Warn( p_vcd_access, 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_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
121 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
122 msg_Dbg( p_vcd_access, message);
125 msg_Warn( p_vcd_access, message);
129 msg_Err( p_vcd_access, 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_vcd= (vcdplayer_t *)p_access->p_sys;
148 const int i_blocks = p_vcd->i_blocks_per_read;
153 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
154 (long unsigned int) p_vcd->i_lsn );
156 /* Allocate a block for the reading */
157 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
159 msg_Err( p_access, "cannot get a new block of size: %i",
160 i_blocks * M2F2_SECTOR_SIZE );
161 block_Release( p_block );
165 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
167 const lsn_t old_lsn = p_vcd->i_lsn;
169 switch ( vcdplayer_read(p_access, (byte_t *) p_block->p_buffer
170 + (i_read*M2F2_SECTOR_SIZE)) ) {
172 /* End reached. Return NULL to indicated this. */
173 block_Release( p_block );
176 /* Some sort of error. Should we increment lsn? to skip block?
178 block_Release( p_block );
180 case READ_STILL_FRAME:
182 dbg_print(INPUT_DBG_STILL, "Handled still event\n");
183 /* Reached the end of a still frame. */
184 byte_t * p_buf = (byte_t *) p_block->p_buffer;
186 p_buf += (i_read*M2F2_SECTOR_SIZE);
187 memset(p_buf, 0, M2F2_SECTOR_SIZE);
190 dbg_print(INPUT_DBG_STILL, "Handled still event");
192 p_vcd->in_still = VLC_TRUE;
193 var_SetInteger( p_access, "state", PAUSE_S );
204 p_access->info.i_pos += (p_vcd->i_lsn - old_lsn) * M2F2_SECTOR_SIZE;
206 /* Update seekpoint */
207 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type )
209 unsigned int i_entry = p_vcd->play_item.num+1;
210 lsn_t i_lsn = vcdinfo_get_entry_lba(p_vcd->vcd, i_entry);
211 if (p_vcd->i_lsn >= i_lsn )
213 const track_t i_track = p_vcd->i_track;
214 p_vcd->play_item.num = i_entry;
215 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "entry change" );
216 VCDSetOrigin( p_access, i_lsn, i_track, &(p_vcd->play_item) );
225 /****************************************************************************
227 ****************************************************************************/
229 VCDSeek( access_t * p_access, int64_t i_pos )
231 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
234 vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
235 const input_title_t *t = p_vcd->p_title[p_access->info.i_title];
237 unsigned int i_entry=VCDINFO_INVALID_ENTRY;
239 /* Next sector to read */
240 p_access->info.i_pos = i_pos;
241 p_vcd->i_lsn = (i_pos / (int64_t)M2F2_SECTOR_SIZE) +
244 switch (p_vcd->play_item.type) {
245 case VCDINFO_ITEM_TYPE_TRACK:
246 case VCDINFO_ITEM_TYPE_ENTRY:
249 p_vcd->b_valid_ep = VLC_FALSE;
253 if( p_vcd->b_valid_ep )
255 for( i_entry = 0 ; i_entry < p_vcd->i_entries ; i_entry ++ )
257 if( p_vcd->i_lsn < p_vcd->p_entries[i_entry] )
259 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
260 "chapter", _("Entry"), "Setting entry" );
266 vcdinfo_itemid_t itemid;
267 itemid.num = i_entry;
268 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
269 VCDSetOrigin(p_access, p_vcd->i_lsn, p_vcd->i_track,
274 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
275 "orig %lu, cur: %lu, offset: %lld, entry %d",
276 (long unsigned int) p_vcd->origin_lsn,
277 (long unsigned int) p_vcd->i_lsn, i_pos,
281 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
283 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
284 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
287 /* Update current seekpoint */
288 if( i_seekpoint != p_access->info.i_seekpoint )
290 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
291 (long unsigned int) i_seekpoint );
292 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
293 p_access->info.i_seekpoint = i_seekpoint;
301 /*****************************************************************************
302 VCDEntryPoints: Reads the information about the entry points on the disc
303 and initializes area information with that.
304 Before calling this track information should have been read in.
305 *****************************************************************************/
307 VCDEntryPoints( access_t * p_access )
309 if (!p_access || !p_access->p_sys) return VLC_FALSE;
312 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
313 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcd->vcd);
314 const track_t i_last_track
315 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcd->vcd))
316 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcd->vcd));
319 if (0 == i_entries) {
320 LOG_ERR ("no entires found -- something is wrong" );
324 p_vcd->p_entries = malloc( sizeof( lsn_t ) * i_entries );
326 if( p_vcd->p_entries == NULL )
328 LOG_ERR ("not enough memory for entry points treatment" );
332 p_vcd->i_entries = i_entries;
334 for( i = 0 ; i < i_entries ; i++ )
336 const track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
337 if( i_track <= i_last_track ) {
338 seekpoint_t *s = vlc_seekpoint_New();
341 snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
343 p_vcd->p_entries[i] = vcdinfo_get_entry_lba(p_vcd->vcd, i);
345 s->psz_name = strdup(psz_entry);
347 (p_vcd->p_entries[i] - vcdinfo_get_track_lba(p_vcd->vcd, i_track))
350 dbg_print( INPUT_DBG_MRL,
351 "%s, lsn %d, byte_offset %ld",
352 s->psz_name, p_vcd->p_entries[i],
353 (unsigned long int) s->i_byte_offset);
354 TAB_APPEND( p_vcd->p_title[i_track-1]->i_seekpoint,
355 p_vcd->p_title[i_track-1]->seekpoint, s );
358 msg_Warn( p_access, "wrong track number found in entry points" );
360 p_vcd->b_valid_ep = VLC_TRUE;
365 /*****************************************************************************
366 * VCDSegments: Reads the information about the segments the disc.
367 *****************************************************************************/
369 VCDSegments( access_t * p_access )
371 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
375 p_vcd->i_segments = vcdinfo_get_num_segments(p_vcd->vcd);
377 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
378 "Segments: %d", p_vcd->i_segments);
380 if ( 0 == p_vcd->i_segments ) return VLC_FALSE;
382 t = p_vcd->p_title[p_vcd->i_titles] = vlc_input_title_New();
385 t->i_size = 0; /* Not sure Segments have a size associated */
386 t->psz_name = strdup(_("Segments"));
388 /* We have one additional segment allocated so we can get the size
389 by subtracting seg[i+1] - seg[i].
391 p_vcd->p_segments = malloc( sizeof( lsn_t ) * (p_vcd->i_segments+1) );
392 if( p_vcd->p_segments == NULL )
394 LOG_ERR ("not enough memory for segment treatment" );
398 for( i = 0 ; i < p_vcd->i_segments ; i++ )
400 char psz_segment[100];
401 seekpoint_t *s = vlc_seekpoint_New();
402 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
404 snprintf( psz_segment, sizeof(psz_segment), "%s%02d", _("Segment "),
407 s->i_byte_offset = 0; /* Not sure what this would mean here */
408 s->psz_name = strdup(psz_segment);
409 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
412 p_vcd->p_segments[p_vcd->i_segments] =
413 p_vcd->p_segments[p_vcd->i_segments-1]+
414 vcdinfo_get_seg_sector_count(p_vcd->vcd, p_vcd->i_segments-1);
419 /*****************************************************************************
420 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
422 We start area addressing for tracks at 1 since the default area 0
423 is reserved for segments.
424 *****************************************************************************/
426 VCDTitles( access_t * p_access )
428 /* We'll assume a VCD has its first MPEG track
429 cdio_get_first_track_num()+1 could be used if one wanted to be
430 very careful about this. Note: cdio_get_first_track() will give the
431 ISO-9660 track before the MPEG tracks.
434 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
437 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
441 for( i = 1 ; i <= p_vcd->i_tracks ; i++ )
443 input_title_t *t = p_vcd->p_title[i-1] = vlc_input_title_New();
445 uint32_t i_secsize = vcdinfo_get_track_sect_count( p_vcd->vcd, i );
447 snprintf( psz_track, sizeof(psz_track), "%s%02d", _("Track "),
450 t->i_size = (i_secsize) * (int64_t) M2F2_SECTOR_SIZE;
451 t->psz_name = strdup(psz_track);
453 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld",
463 /*****************************************************************************
464 VCDLIDs: Reads the LIST IDs from the LOT.
465 *****************************************************************************/
467 VCDLIDs( access_t * p_access )
469 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
471 unsigned int i_lid, i_title;
473 p_vcd->i_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
474 p_vcd->i_lid = VCDINFO_INVALID_ENTRY;
476 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
477 "LIDs: %d", p_vcd->i_lids);
479 if ( 0 == p_vcd->i_lids ) return VLC_FALSE;
481 if (vcdinfo_read_psd (p_vcd->vcd)) {
483 vcdinfo_visit_lot (p_vcd->vcd, VLC_FALSE);
487 We need to change libvcdinfo to be more robust when there are
488 problems reading the extended PSD. Given that area-highlighting and
489 selection features in the extended PSD haven't been implemented,
490 it's best then to not try to read this at all.
492 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
493 vcdinfo_visit_lot (p_vcd->vcd, VLC_TRUE);
497 /* Set up LIDs Navigation Menu */
498 t = vlc_input_title_New();
499 t->b_menu = VLC_TRUE;
500 t->psz_name = strdup( "LIDs" );
502 i_title = p_vcd->i_tracks;
503 for( i_lid = 1 ; i_lid <= p_vcd->i_lids ; i_lid++ )
506 seekpoint_t *s = vlc_seekpoint_New();
508 snprintf( psz_lid, sizeof(psz_lid), "%s%02d", _("LID "),
511 s->i_byte_offset = 0; /* A lid doesn't have an offset
512 size associated with it */
513 s->psz_name = strdup(psz_lid);
514 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
518 #if DYNAMICALLY_ALLOCATED
519 TAB_APPEND( p_vcd->i_titles, p_vcd->p_title, t );
521 p_vcd->p_title[p_vcd->i_titles] = t;
528 /*****************************************************************************
529 * VCDParse: parse command line
530 *****************************************************************************/
532 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
533 /*out*/ vlc_bool_t *play_single_item )
535 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
540 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
541 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
543 *play_single_item = VLC_FALSE;
547 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
552 /* On Win32 we want the VCD access plugin to be explicitly requested,
553 * we end up with lots of problems otherwise */
554 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
557 if( !p_access->psz_path )
562 psz_parser = psz_source = strdup( p_access->psz_path );
564 /* Parse input string :
565 * [device][@[type][title]] */
566 while( *psz_parser && *psz_parser != '@' )
571 if( *psz_parser == '@' )
573 /* Found the divide between the source name and the
574 type+entry number. */
581 switch(*psz_parser) {
583 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
585 *play_single_item = VLC_TRUE;
588 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
590 *play_single_item = VLC_FALSE;
593 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
595 *play_single_item = VLC_TRUE;
598 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
600 *play_single_item = VLC_TRUE;
606 num = strtol( psz_parser, &psz_next, 10 );
607 if ( *psz_parser != '\0' && *psz_next == '\0')
613 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
619 /* No source specified, so figure it out. */
620 if( !p_access->psz_access ) return NULL;
622 psz_source = config_GetPsz( p_access, "vcd" );
624 if( !psz_source || 0==strlen(psz_source) ) {
625 /* Scan for a CD-ROM drive with a VCD in it. */
626 char **cd_drives = cdio_get_devices_with_cap( NULL,
627 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
628 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
630 if( NULL == cd_drives ) return NULL;
631 if( cd_drives[0] == NULL )
633 cdio_free_device_list( cd_drives );
636 psz_source = strdup( cd_drives[0] );
637 cdio_free_device_list( cd_drives );
641 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
642 "source=%s entry=%d type=%d",
643 psz_source, p_itemid->num, p_itemid->type);
649 Set's start origin subsequent seeks/reads
652 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
653 const vcdinfo_itemid_t *p_itemid )
655 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
657 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
658 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
661 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
663 p_access->info.i_pos = ( i_lsn - p_vcd->track_lsn )
665 p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
666 | INPUT_UPDATE_SEEKPOINT;
669 switch (p_vcd->play_item.type) {
670 case VCDINFO_ITEM_TYPE_ENTRY:
671 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
672 "chapter", _("Entry"), "Setting entry/segment");
673 p_access->info.i_title = i_track-1;
674 p_access->info.i_size = p_vcd->p_title[i_track-1]->i_size;
675 p_access->info.i_seekpoint = p_itemid->num;
678 case VCDINFO_ITEM_TYPE_SEGMENT:
679 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
680 "chapter", _("Segment"), "Setting entry/segment");
681 /* The last title entry is the for segments (when segments exist
682 and they must here. The segment seekpoints are stored after
683 the entry seekpoints and (zeroed) lid seekpoints.
685 p_access->info.i_title = p_vcd->i_titles - 1;
686 p_access->info.i_size = 150 * M2F2_SECTOR_SIZE;
687 p_access->info.i_seekpoint = p_vcd->i_entries
688 + p_vcd->i_lids + p_itemid->num;
691 case VCDINFO_ITEM_TYPE_TRACK:
692 p_access->info.i_title = i_track-1;
693 p_access->info.i_size = p_vcd->p_title[i_track-1]->i_size;
694 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcd->vcd,
698 msg_Warn( p_access, "can't set origin for play type %d",
699 p_vcd->play_item.type );
703 VCDUpdateTitle( p_access );
707 /*****************************************************************************
708 * vcd_Open: Opens a VCD device or file initializes, a list of
709 tracks, segements and entry lsns and sizes and returns an opaque handle.
710 *****************************************************************************/
711 static vcdinfo_obj_t *
712 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
714 access_t *p_access = (access_t *)p_this;
715 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
716 vcdinfo_obj_t *p_vcdobj;
720 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
722 if( !psz_dev ) return NULL;
724 actual_dev=strdup(psz_dev);
725 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
733 Save summary info on tracks, segments and entries...
736 if ( 0 < (p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
737 p_vcd->track = (vcdplayer_play_item_info_t *)
738 calloc(p_vcd->i_tracks, sizeof(vcdplayer_play_item_info_t));
740 for (i=0; i<p_vcd->i_tracks; i++) {
741 unsigned int track_num=i+1;
742 p_vcd->track[i].size =
743 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
744 p_vcd->track[i].start_LSN =
745 vcdinfo_get_track_lsn(p_vcdobj, track_num);
750 if ( 0 < (p_vcd->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
751 p_vcd->entry = (vcdplayer_play_item_info_t *)
752 calloc(p_vcd->i_entries, sizeof(vcdplayer_play_item_info_t));
754 for (i=0; i<p_vcd->i_entries; i++) {
755 p_vcd->entry[i].size = vcdinfo_get_entry_sect_count(p_vcdobj, i);
756 p_vcd->entry[i].start_LSN = vcdinfo_get_entry_lba(p_vcdobj, i);
761 if ( 0 < (p_vcd->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
762 p_vcd->segment = (vcdplayer_play_item_info_t *)
763 calloc(p_vcd->i_segments, sizeof(vcdplayer_play_item_info_t));
765 for (i=0; i<p_vcd->i_segments; i++) {
766 p_vcd->segment[i].size = vcdinfo_get_seg_sector_count(p_vcdobj, i);
767 p_vcd->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
770 p_vcd->segment = NULL;
776 /****************************************************************************
777 Update the "varname" variable to i_num without triggering a callback.
778 ****************************************************************************/
780 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
781 const char *p_varname, char *p_label,
782 const char *p_debug_label)
787 const vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
788 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
792 text.psz_string = p_label;
793 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
795 var_Change( p_access, p_varname, i_action, &val, NULL );
799 /*****************************************************************************
801 *****************************************************************************/
803 /*****************************************************************************
805 read in meta-information about VCD: the number of tracks, segments,
806 entries, size and starting information. Then set up state variables so
807 that we read/seek starting at the location specified.
809 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
810 and VLC_EGENERIC for some other error.
811 *****************************************************************************/
813 E_(VCDOpen) ( vlc_object_t *p_this )
815 access_t *p_access = (access_t *)p_this;
818 vcdinfo_itemid_t itemid;
819 vlc_bool_t play_single_item = VLC_FALSE;
821 p_access->pf_read = NULL;
822 p_access->pf_block = VCDReadBlock;
823 p_access->pf_control = VCDControl;
824 p_access->pf_seek = VCDSeek;
826 p_access->info.i_update = 0;
827 p_access->info.i_size = 0;
828 p_access->info.i_pos = 0;
829 p_access->info.b_eof = VLC_FALSE;
830 p_access->info.i_title = 0;
831 p_access->info.i_seekpoint = 0;
833 p_vcd = malloc( sizeof(vcdplayer_t) );
837 LOG_ERR ("out of memory" );
841 p_access->p_sys = (access_sys_t *) p_vcd;
843 /* Set where to log errors messages from libcdio. */
844 p_vcd_access = p_access;
845 cdio_log_set_handler ( cdio_log_handler );
846 vcd_log_set_handler ( vcd_log_handler );
848 psz_source = VCDParse( p_access, &itemid, &play_single_item );
850 if ( NULL == psz_source )
853 return( VLC_EGENERIC );
856 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
857 psz_source, p_access->psz_path );
859 p_vcd->psz_source = strdup(psz_source);
860 p_vcd->i_debug = config_GetInt( p_this,
861 MODULE_STRING "-debug" );
862 p_vcd->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
863 "-blocks-per-read" );
864 p_vcd->in_still = VLC_FALSE;
865 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
866 p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT,
868 p_vcd->p_meta = vlc_meta_New();
869 p_vcd->p_segments = NULL;
870 p_vcd->p_entries = NULL;
874 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
876 msg_Warn( p_access, "could not open %s", psz_source );
880 p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
882 /* Get track information. */
883 p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcd->vcd);
885 if( p_vcd->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcd->i_tracks ) {
886 vcdinfo_close( p_vcd->vcd );
887 LOG_ERR ("no movie tracks found" );
891 /* Build Navigation Title table for the tracks. */
892 VCDTitles( p_access );
894 /* Add into the above entry points as "Chapters". */
895 if( ! VCDEntryPoints( p_access ) )
897 msg_Warn( p_access, "could not read entry points, will not use them" );
898 p_vcd->b_valid_ep = VLC_FALSE;
901 /* Initialize LID info and add that as a menu item */
902 if( ! VCDLIDs( p_access ) )
904 msg_Warn( p_access, "could not read entry LIDs" );
907 /* Do we set PBC (via LID) on? */
909 ( VCDINFO_ITEM_TYPE_LID == itemid.type && p_vcd->i_lids > itemid.num )
911 : VCDINFO_INVALID_ENTRY;
913 /* Initialize segment information and add that a "Track". */
914 VCDSegments( p_access );
916 vcdplayer_play( p_access, itemid );
918 p_access->psz_demux = strdup( "ps" );
921 p_vcd->p_intf = intf_Create( p_access, "vcdx" );
922 p_vcd->p_intf->b_block = VLC_FALSE;
923 intf_RunThread( p_vcd->p_intf );
927 if (play_single_item)
928 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
942 /*****************************************************************************
943 * VCDClose: closes VCD releasing allocated memory.
944 *****************************************************************************/
946 E_(VCDClose) ( vlc_object_t *p_this )
948 access_t *p_access = (access_t *)p_this;
949 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
951 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
953 vcdinfo_close( p_vcd->vcd );
955 FREE_AND_NULL( p_vcd->p_entries );
956 FREE_AND_NULL( p_vcd->p_segments );
957 FREE_AND_NULL( p_vcd->psz_source );
958 FREE_AND_NULL( p_vcd->track );
959 FREE_AND_NULL( p_vcd->segment );
960 FREE_AND_NULL( p_vcd->entry );
963 p_access->p_sys = NULL;
967 /*****************************************************************************
968 * Control: The front-end or vlc engine calls here to ether get
969 * information such as meta information or plugin capabilities or to
970 * issue miscellaneous "set" requests.
971 *****************************************************************************/
972 static int VCDControl( access_t *p_access, int i_query, va_list args )
974 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
978 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
979 "query %d", i_query );
983 /* Pass back a copy of meta information that was gathered when we
984 during the Open/Initialize call.
986 case ACCESS_GET_META:
988 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
990 dbg_print( INPUT_DBG_EVENT, "get meta info" );
992 if ( p_vcd->p_meta ) {
993 *pp_meta = vlc_meta_Duplicate( p_vcd->p_meta );
994 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
996 msg_Warn( p_access, "tried to copy NULL meta info" );
1000 return VLC_EGENERIC;
1002 case ACCESS_CAN_SEEK:
1003 case ACCESS_CAN_FASTSEEK:
1004 case ACCESS_CAN_PAUSE:
1005 case ACCESS_CAN_CONTROL_PACE:
1007 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1009 dbg_print( INPUT_DBG_EVENT,
1010 "seek/fastseek/pause/can_control_pace" );
1011 *pb_bool = VLC_TRUE;
1017 case ACCESS_GET_MTU:
1018 pi_int = (int*)va_arg( args, int * );
1019 *pi_int = (p_vcd->i_blocks_per_read * M2F2_SECTOR_SIZE);
1020 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1023 case ACCESS_GET_PTS_DELAY:
1025 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1026 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1027 * MILLISECONDS_PER_SEC;
1028 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1034 case ACCESS_SET_PAUSE_STATE:
1035 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1039 case ACCESS_GET_TITLE_INFO:
1041 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1042 + strlen(p_vcd->psz_source) + sizeof("@E999")+3;
1043 input_title_t ***ppp_title
1044 = (input_title_t***)va_arg( args, input_title_t*** );
1045 char *psz_mrl = malloc( psz_mrl_max );
1048 pi_int = (int*)va_arg( args, int* );
1050 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1053 if( psz_mrl == NULL ) {
1054 msg_Warn( p_access, "out of memory" );
1056 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1057 VCD_MRL_PREFIX, p_vcd->psz_source);
1058 VCDMetaInfo( p_access, psz_mrl );
1062 /* Duplicate title info */
1063 if( p_vcd->i_titles == 0 )
1065 *pi_int = 0; ppp_title = NULL;
1068 *pi_int = p_vcd->i_titles;
1069 *ppp_title = malloc(sizeof( input_title_t **) * p_vcd->i_titles );
1071 if (!*ppp_title) return VLC_ENOMEM;
1073 for( i = 0; i < p_vcd->i_titles; i++ )
1075 if ( p_vcd->p_title[i] )
1077 vlc_input_title_Duplicate( p_vcd->p_title[i] );
1082 case ACCESS_SET_TITLE:
1083 i = (int)va_arg( args, int );
1085 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1086 if( i != p_access->info.i_title )
1088 vcdinfo_itemid_t itemid;
1089 track_t i_track = i+1;
1090 unsigned int i_entry =
1091 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
1093 /* FIXME! For now we are assuming titles are only
1094 tracks and that track == title+1 */
1095 itemid.num = i_track;
1096 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1098 VCDSetOrigin(p_access,
1099 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
1104 case ACCESS_SET_SEEKPOINT:
1106 input_title_t *t = p_vcd->p_title[p_access->info.i_title];
1107 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1109 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1110 if( t->i_seekpoint > 0 )
1112 track_t i_track = p_access->info.i_title+1;
1115 /* FIXME! For now we are assuming titles are only
1116 tracks and that track == title+1 and we the play
1117 item is entries (not tracks or lids).
1118 We need to generalize all of this.
1121 if (i < p_vcd->i_entries)
1123 p_vcd->play_item.num = i;
1124 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1125 lsn = vcdinfo_get_entry_lba(p_vcd->vcd, i);
1126 } else if ( i < p_vcd->i_entries + p_vcd->i_lids )
1128 p_vcd->play_item.num = i = i - p_vcd->i_entries;
1129 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_LID;
1133 p_vcd->play_item.num = i = i - p_vcd->i_entries
1135 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1136 lsn = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
1139 VCDSetOrigin( p_access,
1140 vcdinfo_get_entry_lba(p_vcd->vcd, i),
1141 i_track, &(p_vcd->play_item) );
1146 case ACCESS_SET_PRIVATE_ID_STATE:
1147 dbg_print( INPUT_DBG_EVENT, "set private id" );
1148 return VLC_EGENERIC;
1151 msg_Warn( p_access, "unimplemented query in control" );
1152 return VLC_EGENERIC;