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 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>
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 #define FREE_AND_NULL(ptr) free(ptr); ptr = NULL;
49 extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
50 const vcdinfo_itemid_t *p_itemid );
52 /*****************************************************************************
54 *****************************************************************************/
56 /* First those which are accessed from outside (via pointers). */
57 static block_t *VCDReadBlock ( access_t * );
59 static int VCDControl ( access_t *p_access, int i_query,
62 /* Now those which are strictly internal */
63 static vlc_bool_t VCDEntryPoints ( access_t * );
64 static vlc_bool_t VCDLIDs ( access_t * );
65 static vlc_bool_t VCDSegments ( access_t * );
66 static int VCDTitles ( access_t * );
67 static char *VCDParse ( access_t *,
68 /*out*/ vcdinfo_itemid_t * p_itemid ,
69 /*out*/ vlc_bool_t *play_single_item );
71 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
72 const char *p_varname, char *p_label,
73 const char *p_debug_label );
75 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
77 /****************************************************************************
79 ****************************************************************************/
81 /* FIXME: This variable is a hack. Would be nice to eliminate the
84 static access_t *p_vcd_access = NULL;
86 /* process messages that originate from libcdio. */
88 cdio_log_handler (cdio_log_level_t level, const char message[])
90 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
94 if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
95 msg_Dbg( p_vcd_access, message);
98 msg_Warn( p_vcd_access, message);
101 case CDIO_LOG_ASSERT:
102 msg_Err( p_vcd_access, message);
105 msg_Warn( p_vcd_access, message,
106 _("The above message had unknown log level"),
112 /* process messages that originate from vcdinfo. */
114 vcd_log_handler (vcd_log_level_t level, const char message[])
116 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
120 if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
121 msg_Dbg( p_vcd_access, message);
124 msg_Warn( p_vcd_access, message);
128 msg_Err( p_vcd_access, message);
131 msg_Warn( p_vcd_access, "%s\n%s %d", message,
132 _("The above message had unknown vcdimager log level"),
138 /*****************************************************************************
139 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
140 NULL is returned if something went wrong.
141 *****************************************************************************/
143 VCDReadBlock( access_t * p_access )
145 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
146 const int i_blocks = p_vcdplayer->i_blocks_per_read;
153 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
154 (long unsigned int) p_vcdplayer->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 p_buf = (uint8_t *) p_block->p_buffer;
166 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
168 vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
170 p_access->info.i_pos += M2F2_SECTOR_SIZE;
172 switch ( read_status ) {
174 /* End reached. Return NULL to indicated this. */
175 /* We also set the postion to the end so the higher level
176 (demux?) doesn't try to keep reading. If everything works out
177 right this shouldn't have to happen.
180 if ( p_access->info.i_pos != p_access->info.i_size ) {
182 "At end but pos (%llu) is not size (%llu). Adjusting.",
183 p_access->info.i_pos, p_access->info.i_size );
184 p_access->info.i_pos = p_access->info.i_size;
188 block_Release( p_block );
192 /* Some sort of error. Should we increment lsn? to skip block?
194 block_Release( p_block );
196 case READ_STILL_FRAME:
198 /* FIXME The below should be done in an event thread.
202 msleep( MILLISECONDS_PER_SEC * *p_buf );
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;
321 /*****************************************************************************
322 VCDEntryPoints: Reads the information about the entry points on the disc
323 and initializes area information with that.
324 Before calling this track information should have been read in.
325 *****************************************************************************/
327 VCDEntryPoints( access_t * p_access )
329 if (!p_access || !p_access->p_sys) return VLC_FALSE;
332 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
333 const unsigned int i_entries =
334 vcdinfo_get_num_entries(p_vcdplayer->vcd);
335 const track_t i_last_track
336 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
337 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
340 if (0 == i_entries) {
341 LOG_ERR ("no entires found -- something is wrong" );
345 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
347 if( p_vcdplayer->p_entries == NULL )
349 LOG_ERR ("not enough memory for entry points treatment" );
353 p_vcdplayer->i_entries = i_entries;
355 for( i = 0 ; i < i_entries ; i++ )
357 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
358 if( i_track <= i_last_track ) {
359 seekpoint_t *s = vlc_seekpoint_New();
362 snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
364 p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
366 s->psz_name = strdup(psz_entry);
368 (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track))
371 dbg_print( INPUT_DBG_MRL,
372 "%s, lsn %d, byte_offset %ld",
373 s->psz_name, p_vcdplayer->p_entries[i],
374 (unsigned long int) s->i_byte_offset);
375 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
376 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
379 msg_Warn( p_access, "wrong track number found in entry points" );
381 p_vcdplayer->b_valid_ep = VLC_TRUE;
386 /*****************************************************************************
387 * VCDSegments: Reads the information about the segments the disc.
388 *****************************************************************************/
390 VCDSegments( access_t * p_access )
392 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
396 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
398 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
399 "Segments: %d", p_vcdplayer->i_segments);
401 if ( 0 == p_vcdplayer->i_segments ) return VLC_FALSE;
403 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
404 p_vcdplayer->i_titles++;
406 t->i_size = 0; /* Not sure Segments have a size associated */
407 t->psz_name = strdup(_("Segments"));
409 /* We have one additional segment allocated so we can get the size
410 by subtracting seg[i+1] - seg[i].
412 p_vcdplayer->p_segments =
413 malloc( sizeof( lsn_t ) * (p_vcdplayer->i_segments+1) );
414 if( p_vcdplayer->p_segments == NULL )
416 LOG_ERR ("not enough memory for segment treatment" );
420 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
422 char psz_segment[100];
423 seekpoint_t *s = vlc_seekpoint_New();
424 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
426 snprintf( psz_segment, sizeof(psz_segment), "%s%02d", _("Segment "),
429 s->i_byte_offset = 0; /* Not sure what this would mean here */
430 s->psz_name = strdup(psz_segment);
431 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
434 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
435 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
436 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
437 p_vcdplayer->i_segments-1);
442 /*****************************************************************************
443 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
445 We start area addressing for tracks at 1 since the default area 0
446 is reserved for segments.
447 *****************************************************************************/
449 VCDTitles( access_t * p_access )
451 /* We'll assume a VCD has its first MPEG track
452 cdio_get_first_track_num()+1 could be used if one wanted to be
453 very careful about this. Note: cdio_get_first_track() will give the
454 ISO-9660 track before the MPEG tracks.
457 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
460 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
463 p_vcdplayer->i_titles = 0;
464 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
466 input_title_t *t = p_vcdplayer->p_title[i-1] =
467 vlc_input_title_New();
470 snprintf( psz_track, sizeof(psz_track), "%s%02d", _("Track "),
472 t->i_size = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
474 * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
475 t->psz_name = strdup(psz_track);
477 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld", i, t->i_size );
479 p_vcdplayer->i_titles++;
486 /*****************************************************************************
487 VCDLIDs: Reads the LIST IDs from the LOT.
488 *****************************************************************************/
490 VCDLIDs( access_t * p_access )
492 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
494 unsigned int i_lid, i_title;
496 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
497 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
499 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
500 "LIDs: %d", p_vcdplayer->i_lids);
502 if ( 0 == p_vcdplayer->i_lids ) return VLC_FALSE;
504 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
506 vcdinfo_visit_lot (p_vcdplayer->vcd, false);
510 We need to change libvcdinfo to be more robust when there are
511 problems reading the extended PSD. Given that area-highlighting and
512 selection features in the extended PSD haven't been implemented,
513 it's best then to not try to read this at all.
515 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
516 vcdinfo_visit_lot (p_vcdplayer->vcd, VLC_TRUE);
520 /* Set up LIDs Navigation Menu */
521 t = vlc_input_title_New();
522 t->b_menu = VLC_TRUE;
523 t->psz_name = strdup( "LIDs" );
525 i_title = p_vcdplayer->i_tracks;
526 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
529 seekpoint_t *s = vlc_seekpoint_New();
531 snprintf( psz_lid, sizeof(psz_lid), "%s%02d", _("LID "),
534 s->i_byte_offset = 0; /* A lid doesn't have an offset
535 size associated with it */
536 s->psz_name = strdup(psz_lid);
537 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
540 #if DYNAMICALLY_ALLOCATED
541 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
543 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
544 p_vcdplayer->i_titles++;
550 /*****************************************************************************
551 * VCDParse: parse command line
552 *****************************************************************************/
554 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
555 /*out*/ vlc_bool_t *play_single_item )
557 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
562 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
563 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
565 *play_single_item = VLC_FALSE;
569 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
574 /* On Win32 we want the VCD access plugin to be explicitly requested,
575 * we end up with lots of problems otherwise */
576 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
579 if( !p_access->psz_path )
584 psz_parser = psz_source = strdup( p_access->psz_path );
586 /* Parse input string :
587 * [device][@[type][title]] */
588 while( *psz_parser && *psz_parser != '@' )
593 if( *psz_parser == '@' )
595 /* Found the divide between the source name and the
596 type+entry number. */
603 switch(*psz_parser) {
605 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
607 *play_single_item = VLC_TRUE;
610 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
612 *play_single_item = VLC_FALSE;
615 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
617 *play_single_item = VLC_TRUE;
620 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
622 *play_single_item = VLC_TRUE;
628 num = strtol( psz_parser, &psz_next, 10 );
629 if ( *psz_parser != '\0' && *psz_next == '\0')
635 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
641 /* No source specified, so figure it out. */
642 if( !p_access->psz_access ) return NULL;
644 psz_source = config_GetPsz( p_access, "vcd" );
646 if( !psz_source || 0==strlen(psz_source) ) {
647 /* Scan for a CD-ROM drive with a VCD in it. */
648 char **cd_drives = cdio_get_devices_with_cap( NULL,
649 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
650 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
652 if( NULL == cd_drives ) return NULL;
653 if( cd_drives[0] == NULL )
655 cdio_free_device_list( cd_drives );
658 psz_source = strdup( cd_drives[0] );
659 cdio_free_device_list( cd_drives );
663 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
664 "source=%s entry=%d type=%d",
665 psz_source, p_itemid->num, p_itemid->type);
671 Sets start origin for subsequent seeks/reads
674 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
675 const vcdinfo_itemid_t *p_itemid )
677 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
679 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
680 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
683 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
685 switch (p_vcdplayer->play_item.type) {
686 case VCDINFO_ITEM_TYPE_ENTRY:
687 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
688 "chapter", _("Entry"), "Setting entry/segment");
689 p_access->info.i_title = i_track-1;
690 if (p_vcdplayer->b_track_length)
692 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
693 p_access->info.i_pos = (int64_t) i_lsn * M2F2_SECTOR_SIZE;
695 p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
696 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd, p_itemid->num);
697 p_access->info.i_pos = 0;
699 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %llu, pos: %llu",
700 p_access->info.i_size, p_access->info.i_pos );
701 p_access->info.i_seekpoint = p_itemid->num;
704 case VCDINFO_ITEM_TYPE_SEGMENT:
705 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
706 "chapter", _("Segment"), "Setting entry/segment");
707 /* The last title entry is the for segments (when segments exist
708 and they must here. The segment seekpoints are stored after
709 the entry seekpoints and (zeroed) lid seekpoints.
711 p_access->info.i_title = p_vcdplayer->i_titles - 1;
712 p_access->info.i_size = 0; /* No seeking on stills, please. */
713 p_access->info.i_pos = 0;
714 p_access->info.i_seekpoint = p_vcdplayer->i_entries
715 + p_vcdplayer->i_lids + p_itemid->num;
718 case VCDINFO_ITEM_TYPE_TRACK:
719 p_access->info.i_title = i_track-1;
720 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
721 p_access->info.i_pos = 0;
722 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
727 msg_Warn( p_access, "can't set origin for play type %d",
728 p_vcdplayer->play_item.type );
731 p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
732 | INPUT_UPDATE_SEEKPOINT;
734 VCDUpdateTitle( p_access );
738 /*****************************************************************************
739 * vcd_Open: Opens a VCD device or file initializes, a list of
740 tracks, segements and entry lsns and sizes and returns an opaque handle.
741 *****************************************************************************/
742 static vcdinfo_obj_t *
743 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
745 access_t *p_access = (access_t *)p_this;
746 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
747 vcdinfo_obj_t *p_vcdobj;
751 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
753 if( !psz_dev ) return NULL;
755 actual_dev=strdup(psz_dev);
756 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
764 Save summary info on tracks, segments and entries...
767 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
768 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
769 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
771 for (i=0; i<p_vcdplayer->i_tracks; i++) {
772 unsigned int track_num=i+1;
773 p_vcdplayer->track[i].size =
774 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
775 p_vcdplayer->track[i].start_LSN =
776 vcdinfo_get_track_lsn(p_vcdobj, track_num);
779 p_vcdplayer->track = NULL;
781 if ( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
782 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
783 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
785 for (i=0; i<p_vcdplayer->i_entries; i++) {
786 p_vcdplayer->entry[i].size =
787 vcdinfo_get_entry_sect_count(p_vcdobj, i);
788 p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lsn(p_vcdobj, i);
791 p_vcdplayer->entry = NULL;
793 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
794 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
795 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
797 for (i=0; i<p_vcdplayer->i_segments; i++) {
798 p_vcdplayer->segment[i].size =
799 vcdinfo_get_seg_sector_count(p_vcdobj, i);
800 p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
803 p_vcdplayer->segment = NULL;
808 /****************************************************************************
809 Update the "varname" variable to i_num without triggering a callback.
810 ****************************************************************************/
812 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
813 const char *p_varname, char *p_label,
814 const char *p_debug_label)
819 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
820 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
824 text.psz_string = p_label;
825 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
827 var_Change( p_access, p_varname, i_action, &val, NULL );
831 /*****************************************************************************
833 *****************************************************************************/
835 /*****************************************************************************
837 read in meta-information about VCD: the number of tracks, segments,
838 entries, size and starting information. Then set up state variables so
839 that we read/seek starting at the location specified.
841 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
842 and VLC_EGENERIC for some other error.
843 *****************************************************************************/
845 VCDOpen ( vlc_object_t *p_this )
847 access_t *p_access = (access_t *)p_this;
848 vcdplayer_t *p_vcdplayer;
850 vcdinfo_itemid_t itemid;
851 vlc_bool_t play_single_item = VLC_FALSE;
853 p_access->pf_read = NULL;
854 p_access->pf_block = VCDReadBlock;
855 p_access->pf_control = VCDControl;
856 p_access->pf_seek = VCDSeek;
858 p_access->info.i_update = 0;
859 p_access->info.i_size = 0;
860 p_access->info.i_pos = 0;
861 p_access->info.b_eof = VLC_FALSE;
862 p_access->info.i_title = 0;
863 p_access->info.i_seekpoint = 0;
865 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
867 if( p_vcdplayer == NULL )
869 LOG_ERR ("out of memory" );
873 p_vcdplayer->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
874 p_access->p_sys = (access_sys_t *) p_vcdplayer;
876 /* Set where to log errors messages from libcdio. */
877 p_vcd_access = p_access;
878 cdio_log_set_handler ( cdio_log_handler );
879 vcd_log_set_handler ( vcd_log_handler );
881 psz_source = VCDParse( p_access, &itemid, &play_single_item );
883 if ( NULL == psz_source )
886 return( VLC_EGENERIC );
889 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
890 psz_source, p_access->psz_path );
892 p_vcdplayer->psz_source = strdup(psz_source);
893 p_vcdplayer->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
894 "-blocks-per-read" );
895 p_vcdplayer->b_track_length = config_GetInt( p_this, MODULE_STRING
897 p_vcdplayer->in_still = VLC_FALSE;
898 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
899 p_vcdplayer->p_input = vlc_object_find( p_access,
902 p_vcdplayer->p_meta = vlc_meta_New();
903 p_vcdplayer->p_segments = NULL;
904 p_vcdplayer->p_entries = NULL;
908 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
913 p_vcdplayer->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcdplayer->vcd);;
915 /* Get track information. */
916 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
918 if( p_vcdplayer->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcdplayer->i_tracks ) {
919 vcdinfo_close( p_vcdplayer->vcd );
920 LOG_ERR ("no movie tracks found" );
924 /* Build Navigation Title table for the tracks. */
925 VCDTitles( p_access );
927 /* Add into the above entry points as "Chapters". */
928 if( ! VCDEntryPoints( p_access ) )
930 msg_Warn( p_access, "could not read entry points, will not use them" );
931 p_vcdplayer->b_valid_ep = VLC_FALSE;
934 /* Initialize LID info and add that as a menu item */
935 if( ! VCDLIDs( p_access ) )
937 msg_Warn( p_access, "could not read entry LIDs" );
940 /* Do we set PBC (via LID) on? */
942 ( VCDINFO_ITEM_TYPE_LID == itemid.type
943 && p_vcdplayer->i_lids > itemid.num )
945 : VCDINFO_INVALID_ENTRY;
947 /* Initialize segment information and add that a "Track". */
948 VCDSegments( p_access );
950 vcdplayer_play( p_access, itemid );
952 p_access->psz_demux = strdup( "ps" );
955 if (play_single_item)
956 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
961 p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
962 p_vcdplayer->p_intf->b_block = VLC_FALSE;
964 p_vcdplayer->p_access = p_access;
967 intf_RunThread( p_vcdplayer->p_intf );
974 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
980 /*****************************************************************************
981 * VCDClose: closes VCD releasing allocated memory.
982 *****************************************************************************/
984 VCDClose ( vlc_object_t *p_this )
986 access_t *p_access = (access_t *)p_this;
987 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
989 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
993 for (i=0 ; i<p_vcdplayer->i_titles; i++)
994 if (p_vcdplayer->p_title[i])
995 free(p_vcdplayer->p_title[i]->psz_name);
998 vcdinfo_close( p_vcdplayer->vcd );
1000 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
1002 FREE_AND_NULL( p_vcdplayer->p_entries );
1003 FREE_AND_NULL( p_vcdplayer->p_segments );
1004 FREE_AND_NULL( p_vcdplayer->psz_source );
1005 FREE_AND_NULL( p_vcdplayer->track );
1006 FREE_AND_NULL( p_vcdplayer->segment );
1007 FREE_AND_NULL( p_vcdplayer->entry );
1008 FREE_AND_NULL( p_access->psz_demux );
1009 FREE_AND_NULL( p_vcdplayer );
1010 p_vcd_access = NULL;
1013 /*****************************************************************************
1014 * Control: The front-end or vlc engine calls here to ether get
1015 * information such as meta information or plugin capabilities or to
1016 * issue miscellaneous "set" requests.
1017 *****************************************************************************/
1018 static int VCDControl( access_t *p_access, int i_query, va_list args )
1020 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1024 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1025 "query %d", i_query );
1029 /* Pass back a copy of meta information that was gathered when we
1030 during the Open/Initialize call.
1032 case ACCESS_GET_META:
1034 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1036 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1038 if ( p_vcdplayer->p_meta ) {
1039 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1040 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1042 msg_Warn( p_access, "tried to copy NULL meta info" );
1046 return VLC_EGENERIC;
1048 case ACCESS_CAN_SEEK:
1049 case ACCESS_CAN_FASTSEEK:
1050 case ACCESS_CAN_PAUSE:
1051 case ACCESS_CAN_CONTROL_PACE:
1053 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1055 dbg_print( INPUT_DBG_EVENT,
1056 "seek/fastseek/pause/can_control_pace" );
1057 *pb_bool = VLC_TRUE;
1063 case ACCESS_GET_MTU:
1064 pi_int = (int*)va_arg( args, int * );
1065 *pi_int = (p_vcdplayer->i_blocks_per_read * M2F2_SECTOR_SIZE);
1066 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1069 case ACCESS_GET_PTS_DELAY:
1071 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1072 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1073 * MILLISECONDS_PER_SEC;
1074 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1080 case ACCESS_SET_PAUSE_STATE:
1081 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1085 case ACCESS_GET_TITLE_INFO:
1087 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1088 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1089 input_title_t ***ppp_title
1090 = (input_title_t***)va_arg( args, input_title_t*** );
1091 char *psz_mrl = malloc( psz_mrl_max );
1094 pi_int = (int*)va_arg( args, int* );
1096 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1097 p_vcdplayer->i_titles );
1099 if( psz_mrl == NULL ) {
1100 msg_Warn( p_access, "out of memory" );
1102 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1103 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1104 VCDMetaInfo( p_access, psz_mrl );
1108 /* Duplicate title info */
1109 if( p_vcdplayer->i_titles == 0 )
1111 *pi_int = 0; ppp_title = NULL;
1114 *pi_int = p_vcdplayer->i_titles;
1115 *ppp_title = malloc( sizeof( input_title_t **)
1116 * p_vcdplayer->i_titles );
1118 if (!*ppp_title) return VLC_ENOMEM;
1120 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1122 if ( p_vcdplayer->p_title[i] )
1124 vlc_input_title_Duplicate( p_vcdplayer->p_title[i] );
1129 case ACCESS_SET_TITLE:
1130 i = (int)va_arg( args, int );
1132 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1133 if( i != p_access->info.i_title )
1135 vcdinfo_itemid_t itemid;
1136 track_t i_track = i+1;
1137 unsigned int i_entry =
1138 vcdinfo_track_get_entry( p_vcdplayer->vcd, i_track);
1140 /* FIXME! For now we are assuming titles are only
1141 tracks and that track == title+1 */
1142 itemid.num = i_track;
1143 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1145 VCDSetOrigin(p_access,
1146 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry),
1151 case ACCESS_SET_SEEKPOINT:
1153 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1154 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1156 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1157 if( t->i_seekpoint > 0 )
1159 track_t i_track = p_access->info.i_title+1;
1162 /* FIXME! For now we are assuming titles are only
1163 tracks and that track == title+1 and we the play
1164 item is entries (not tracks or lids).
1165 We need to generalize all of this.
1168 if (i < p_vcdplayer->i_entries)
1170 p_vcdplayer->play_item.num = i;
1171 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1172 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1173 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1175 p_vcdplayer->play_item.num = i
1176 = i - p_vcdplayer->i_entries;
1177 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1181 p_vcdplayer->play_item.num = i
1182 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1183 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1184 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1187 VCDSetOrigin( p_access,
1188 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i),
1189 i_track, &(p_vcdplayer->play_item) );
1194 case ACCESS_SET_PRIVATE_ID_STATE:
1195 dbg_print( INPUT_DBG_EVENT, "set private id" );
1196 return VLC_EGENERIC;
1199 msg_Warn( p_access, "unimplemented query in control" );
1200 return VLC_EGENERIC;