1 /*****************************************************************************
2 * access.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 VLC authors and 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 it
14 * under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_interface.h>
38 #include <vlc_input.h>
39 #include <vlc_access.h>
40 #include <vlc_charset.h>
42 #include <cdio/cdio.h>
43 #include <cdio/cd_types.h>
44 #include <cdio/logging.h>
45 #include <cdio/util.h>
46 #include <libvcd/info.h>
47 #include <libvcd/logging.h>
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 bool VCDEntryPoints ( access_t * );
64 static bool VCDLIDs ( access_t * );
65 static bool VCDSegments ( access_t * );
66 static int VCDTitles ( access_t * );
67 static char *VCDParse ( access_t *,
68 /*out*/ vcdinfo_itemid_t * p_itemid ,
69 /*out*/ bool *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, "%s", message);
98 msg_Warn( p_vcd_access, "%s", message);
101 case CDIO_LOG_ASSERT:
102 msg_Err( p_vcd_access, "%s", message);
105 msg_Warn( p_vcd_access, "%s\n%s %d", message,
106 "The above message had unknown log level", level);
111 /* process messages that originate from vcdinfo. */
113 vcd_log_handler (vcd_log_level_t level, const char message[])
115 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
119 if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
120 msg_Dbg( p_vcd_access, "%s", message);
123 msg_Warn( p_vcd_access, "%s", message);
127 msg_Err( p_vcd_access, "%s", message);
130 msg_Warn( p_vcd_access, "%s\n%s %d", message,
131 "The above message had unknown vcdimager log level", 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;
149 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
150 (long unsigned int) p_vcdplayer->i_lsn );
152 /* Allocate a block for the reading */
153 if( !( p_block = block_Alloc( i_blocks * M2F2_SECTOR_SIZE ) ) )
155 msg_Err( p_access, "cannot get a new block of size: %i",
156 i_blocks * M2F2_SECTOR_SIZE );
157 block_Release( p_block );
161 p_buf = (uint8_t *) p_block->p_buffer;
162 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
164 vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
166 p_access->info.i_pos += M2F2_SECTOR_SIZE;
168 switch ( read_status ) {
170 /* End reached. Return NULL to indicated this. */
171 /* We also set the postion to the end so the higher level
172 (demux?) doesn't try to keep reading. If everything works out
173 right this shouldn't have to happen.
176 if( p_access->info.i_pos != p_access->info.i_size ) {
178 "At end but pos (%llu) is not size (%llu). Adjusting.",
179 p_access->info.i_pos, p_access->info.i_size );
180 p_access->info.i_pos = p_access->info.i_size;
184 block_Release( p_block );
188 /* Some sort of error. Should we increment lsn? to skip block? */
189 block_Release( p_block );
191 case READ_STILL_FRAME:
192 /* FIXME The below should be done in an event thread.
196 msleep( INT64_C(1000) * *p_buf );
197 VCDSetOrigin(p_access, p_vcdplayer->origin_lsn,
198 p_vcdplayer->i_track, &(p_vcdplayer->play_item));
199 // p_vcd->in_still = false;
200 dbg_print(INPUT_DBG_STILL, "still wait time done");
203 block_Release( p_block );
212 p_buf += M2F2_SECTOR_SIZE;
213 /* Update seekpoint */
214 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
216 size_t i_entry = p_vcdplayer->play_item.num+1;
217 lsn_t i_lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
218 if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
220 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
221 "entry change to %zu, current LSN %u >= end %u",
222 i_entry, p_vcdplayer->i_lsn, i_lsn);
224 p_vcdplayer->play_item.num = i_entry;
226 VCDSetOrigin( p_access, i_lsn, p_vcdplayer->i_track,
227 &(p_vcdplayer->play_item) );
236 /****************************************************************************
238 ****************************************************************************/
240 VCDSeek( access_t * p_access, uint64_t i_pos )
242 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
244 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
245 const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
246 unsigned int i_entry = VCDINFO_INVALID_ENTRY;
249 /* Next sector to read */
250 p_access->info.i_pos = i_pos;
251 p_vcdplayer->i_lsn = (i_pos / (uint64_t) M2F2_SECTOR_SIZE) +
252 p_vcdplayer->origin_lsn;
254 switch (p_vcdplayer->play_item.type)
256 case VCDINFO_ITEM_TYPE_TRACK:
257 case VCDINFO_ITEM_TYPE_ENTRY:
260 p_vcdplayer->b_valid_ep = false;
265 if( p_vcdplayer->b_valid_ep )
267 for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
269 if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
271 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
272 "chapter", _("Entry"), "Setting entry" );
278 vcdinfo_itemid_t itemid;
279 itemid.num = i_entry;
280 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
281 VCDSetOrigin(p_access, p_vcdplayer->i_lsn,
282 p_vcdplayer->i_track, &itemid);
286 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
287 "orig %lu, cur: %lu, offset: %"PRIi64", entry %d",
288 (long unsigned int) p_vcdplayer->origin_lsn,
289 (long unsigned int) p_vcdplayer->i_lsn, i_pos,
293 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
295 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
296 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
299 /* Update current seekpoint */
300 if( i_seekpoint != p_access->info.i_seekpoint )
302 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
303 (long unsigned int) i_seekpoint );
304 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
305 p_access->info.i_seekpoint = i_seekpoint;
308 p_access->info.b_eof = false;
312 /*****************************************************************************
313 VCDEntryPoints: Reads the information about the entry points on the disc
314 and initializes area information with that.
315 Before calling this track information should have been read in.
316 *****************************************************************************/
318 VCDEntryPoints( access_t * p_access )
320 if (!p_access || !p_access->p_sys) return false;
322 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
323 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdplayer->vcd);
324 const track_t i_last_track
325 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
326 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
329 if (0 == i_entries) {
330 LOG_ERR ("no entires found -- something is wrong" );
334 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
336 if( p_vcdplayer->p_entries == NULL )
338 LOG_ERR ("not enough memory for entry points treatment" );
342 p_vcdplayer->i_entries = i_entries;
344 for( i = 0 ; i < i_entries ; i++ )
346 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
347 if( i_track <= i_last_track )
349 seekpoint_t *s = vlc_seekpoint_New();
352 snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i );
354 p_vcdplayer->p_entries[i] =
355 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
357 s->psz_name = strdup(psz_entry);
358 s->i_byte_offset = (p_vcdplayer->p_entries[i]
359 - vcdinfo_get_track_lsn(p_vcdplayer->vcd,i_track))
362 dbg_print( INPUT_DBG_MRL, "%s, lsn %d, byte_offset %"PRId64"",
363 s->psz_name, p_vcdplayer->p_entries[i],
365 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
366 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
369 msg_Warn( p_access, "wrong track number found in entry points" );
371 p_vcdplayer->b_valid_ep = true;
375 /*****************************************************************************
376 * VCDSegments: Reads the information about the segments the disc.
377 *****************************************************************************/
379 VCDSegments( access_t * p_access )
381 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
385 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
387 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
388 "Segments: %d", p_vcdplayer->i_segments);
390 if ( 0 == p_vcdplayer->i_segments ) return false;
392 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
393 p_vcdplayer->i_titles++;
395 t->i_size = 0; /* Not sure Segments have a size associated */
396 t->psz_name = strdup(_("Segments"));
398 /* We have one additional segment allocated so we can get the size
399 by subtracting seg[i+1] - seg[i].
401 p_vcdplayer->p_segments=malloc(sizeof(lsn_t)*(p_vcdplayer->i_segments+1));
402 if( p_vcdplayer->p_segments == NULL )
404 LOG_ERR ("not enough memory for segment treatment" );
408 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
410 char psz_segment[100];
411 seekpoint_t *s = vlc_seekpoint_New();
412 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
414 snprintf( psz_segment, sizeof(psz_segment), "%s %02d", _("Segment"),
417 s->i_byte_offset = 0; /* Not sure what this would mean here */
418 s->psz_name = strdup(psz_segment);
419 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
422 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
423 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
424 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
425 p_vcdplayer->i_segments-1);
430 /*****************************************************************************
431 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
433 We start area addressing for tracks at 1 since the default area 0
434 is reserved for segments.
435 *****************************************************************************/
437 VCDTitles( access_t * p_access )
439 /* We'll assume a VCD has its first MPEG track
440 cdio_get_first_track_num()+1 could be used if one wanted to be
441 very careful about this. Note: cdio_get_first_track() will give the
442 ISO-9660 track before the MPEG tracks.
445 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
448 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
451 p_vcdplayer->i_titles = 0;
452 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
454 input_title_t *t = p_vcdplayer->p_title[i-1] =
455 vlc_input_title_New();
458 snprintf( psz_track, sizeof(psz_track), "%s %02d", _("Track"), i );
459 t->i_size = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
460 i ) * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
461 t->psz_name = strdup(psz_track);
463 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %"PRIi64, i, t->i_size );
465 p_vcdplayer->i_titles++;
472 /*****************************************************************************
473 VCDLIDs: Reads the LIST IDs from the LOT.
474 *****************************************************************************/
476 VCDLIDs( access_t * p_access )
478 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
480 unsigned int i_lid, i_title;
482 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
483 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
485 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
486 "LIDs: %d", p_vcdplayer->i_lids);
488 if ( 0 == p_vcdplayer->i_lids ) return false;
490 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
492 vcdinfo_visit_lot (p_vcdplayer->vcd, false);
496 We need to change libvcdinfo to be more robust when there are
497 problems reading the extended PSD. Given that area-highlighting and
498 selection features in the extended PSD haven't been implemented,
499 it's best then to not try to read this at all.
501 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
502 vcdinfo_visit_lot (p_vcdplayer->vcd, true);
506 /* Set up LIDs Navigation Menu */
507 t = vlc_input_title_New();
509 t->psz_name = strdup( "LIDs" );
511 i_title = p_vcdplayer->i_tracks;
512 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
515 seekpoint_t *s = vlc_seekpoint_New();
517 snprintf( psz_lid, sizeof(psz_lid), "%s %02d", _("LID"), i_lid );
519 s->i_byte_offset = 0; /* A lid doesn't have an offset
520 size associated with it */
521 s->psz_name = strdup(psz_lid);
522 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
525 #ifdef DYNAMICALLY_ALLOCATED
526 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
528 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
529 p_vcdplayer->i_titles++;
535 /*****************************************************************************
536 * VCDParse: parse command line
537 *****************************************************************************/
539 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
540 /*out*/ bool *play_single_item )
542 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
547 if( var_InheritBool( p_access, MODULE_STRING "-PBC" ) ) {
548 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
550 *play_single_item = false;
554 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
559 /* On Win32 we want the VCD access plugin to be explicitly requested,
560 * we end up with lots of problems otherwise */
561 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
564 if( !p_access->psz_location )
569 psz_parser = psz_source = strdup( p_access->psz_location );
571 /* Parse input string :
572 * [device][@[type][title]] */
573 while( *psz_parser && *psz_parser != '@' )
578 if( *psz_parser == '@' )
580 /* Found the divide between the source name and the
581 type+entry number. */
587 switch(*psz_parser) {
589 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
591 *play_single_item = true;
594 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
596 *play_single_item = false;
599 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
601 *play_single_item = true;
604 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
606 *play_single_item = true;
612 num = strtol( psz_parser, &psz_next, 10 );
613 if ( *psz_parser != '\0' && *psz_next == '\0')
619 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
626 /* No source specified, so figure it out. */
627 if( !p_access->psz_access ) return NULL;
629 psz_source = var_InheritString( p_access, "vcd" );
633 /* Scan for a CD-ROM drive with a VCD in it. */
634 char **cd_drives = cdio_get_devices_with_cap(NULL,
635 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
636 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
638 if( NULL == cd_drives ) return NULL;
639 if( cd_drives[0] == NULL )
641 cdio_free_device_list( cd_drives );
644 psz_source = strdup( cd_drives[0] );
645 cdio_free_device_list( cd_drives );
649 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
650 "source=%s entry=%d type=%d",
651 psz_source, p_itemid->num, p_itemid->type);
657 Sets start origin for subsequent seeks/reads
660 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
661 const vcdinfo_itemid_t *p_itemid )
663 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
665 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
666 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn, i_track );
668 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
670 switch (p_vcdplayer->play_item.type)
672 case VCDINFO_ITEM_TYPE_ENTRY:
673 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
674 "chapter", _("Entry"), "Setting entry/segment");
675 p_access->info.i_title = i_track-1;
676 if (p_vcdplayer->b_track_length)
678 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
679 p_access->info.i_pos = (uint64_t) M2F2_SECTOR_SIZE *
680 (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track)-i_lsn);
682 p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
683 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd,p_itemid->num);
684 p_access->info.i_pos = 0;
686 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %"PRIu64", pos: %"PRIu64,
687 p_access->info.i_size, p_access->info.i_pos );
688 p_access->info.i_seekpoint = p_itemid->num;
691 case VCDINFO_ITEM_TYPE_SEGMENT:
692 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
693 "chapter", _("Segment"), "Setting entry/segment");
694 /* The last title entry is the for segments (when segments exist
695 and they must here. The segment seekpoints are stored after
696 the entry seekpoints and (zeroed) lid seekpoints.
698 p_access->info.i_title = p_vcdplayer->i_titles - 1;
699 p_access->info.i_size = 0; /* No seeking on stills, please. */
700 p_access->info.i_pos = 0;
701 p_access->info.i_seekpoint = p_vcdplayer->i_entries
702 + p_vcdplayer->i_lids + p_itemid->num;
705 case VCDINFO_ITEM_TYPE_TRACK:
706 p_access->info.i_title = i_track-1;
707 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
708 p_access->info.i_pos = 0;
709 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
714 msg_Warn( p_access, "can't set origin for play type %d",
715 p_vcdplayer->play_item.type );
718 p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SEEKPOINT;
720 VCDUpdateTitle( p_access );
724 /*****************************************************************************
725 * vcd_Open: Opens a VCD device or file initializes, a list of
726 tracks, segements and entry lsns and sizes and returns an opaque handle.
727 *****************************************************************************/
728 static vcdinfo_obj_t *
729 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
731 access_t *p_access = (access_t *)p_this;
732 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
733 vcdinfo_obj_t *p_vcdobj;
737 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
739 if( !psz_dev ) return NULL;
741 actual_dev= ToLocaleDup(psz_dev);
742 if( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
751 Save summary info on tracks, segments and entries...
754 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) )
756 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
757 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
759 for (i=0; i<p_vcdplayer->i_tracks; i++)
761 unsigned int track_num=i+1;
762 p_vcdplayer->track[i].size =
763 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
764 p_vcdplayer->track[i].start_LSN =
765 vcdinfo_get_track_lsn(p_vcdobj, track_num);
768 p_vcdplayer->track = NULL;
770 if( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) )
772 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
773 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
775 for (i=0; i<p_vcdplayer->i_entries; i++)
777 p_vcdplayer->entry[i].size =
778 vcdinfo_get_entry_sect_count(p_vcdobj, i);
779 p_vcdplayer->entry[i].start_LSN =
780 vcdinfo_get_entry_lsn(p_vcdobj, i);
783 p_vcdplayer->entry = NULL;
785 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) )
787 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
788 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
790 for (i=0; i<p_vcdplayer->i_segments; i++)
792 p_vcdplayer->segment[i].size =
793 vcdinfo_get_seg_sector_count(p_vcdobj, i);
794 p_vcdplayer->segment[i].start_LSN =
795 vcdinfo_get_seg_lsn(p_vcdobj, i);
798 p_vcdplayer->segment = NULL;
803 /****************************************************************************
804 Update the "varname" variable to i_num without triggering a callback.
805 ****************************************************************************/
807 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
808 const char *p_varname, char *p_label,
809 const char *p_debug_label)
815 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
816 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
821 text.psz_string = p_label;
822 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
824 var_Change( p_access, p_varname, i_action, &val, NULL );
828 /*****************************************************************************
830 *****************************************************************************/
832 /*****************************************************************************
834 read in meta-information about VCD: the number of tracks, segments,
835 entries, size and starting information. Then set up state variables so
836 that we read/seek starting at the location specified.
838 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
839 and VLC_EGENERIC for some other error.
840 *****************************************************************************/
842 VCDOpen ( vlc_object_t *p_this )
844 access_t *p_access = (access_t *)p_this;
845 vcdplayer_t *p_vcdplayer;
847 vcdinfo_itemid_t itemid;
848 bool play_single_item = false;
850 p_access->pf_read = NULL;
851 p_access->pf_block = VCDReadBlock;
852 p_access->pf_control = VCDControl;
853 p_access->pf_seek = VCDSeek;
855 p_access->info.i_update = 0;
856 p_access->info.i_size = 0;
857 p_access->info.i_pos = 0;
858 p_access->info.b_eof = false;
859 p_access->info.i_title = 0;
860 p_access->info.i_seekpoint = 0;
862 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
864 if( p_vcdplayer == NULL )
867 p_vcdplayer->i_debug = var_InheritInteger( p_this, MODULE_STRING "-debug" );
868 p_access->p_sys = (access_sys_t *) p_vcdplayer;
870 /* Set where to log errors messages from libcdio. */
871 p_vcd_access = p_access;
872 cdio_log_set_handler ( cdio_log_handler );
873 vcd_log_set_handler ( vcd_log_handler );
875 psz_source = VCDParse( p_access, &itemid, &play_single_item );
877 if ( NULL == psz_source )
880 return( VLC_EGENERIC );
883 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
884 psz_source, p_access->psz_location );
886 p_vcdplayer->psz_source = strdup(psz_source);
887 p_vcdplayer->i_blocks_per_read = var_InheritInteger( p_this, MODULE_STRING
888 "-blocks-per-read" );
889 p_vcdplayer->b_track_length = var_InheritInteger( p_this, MODULE_STRING
891 p_vcdplayer->in_still = false;
892 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
893 p_vcdplayer->p_input = access_GetParentInput( p_access );
894 // p_vcdplayer->p_meta = vlc_meta_New();
895 p_vcdplayer->p_segments = NULL;
896 p_vcdplayer->p_entries = NULL;
900 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
905 p_vcdplayer->b_svd = vcdinfo_get_tracksSVD(p_vcdplayer->vcd);
907 /* Get track information. */
908 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
910 if( p_vcdplayer->i_tracks<1 || CDIO_INVALID_TRACK==p_vcdplayer->i_tracks )
912 vcdinfo_close( p_vcdplayer->vcd );
913 LOG_ERR ("no movie tracks found" );
917 /* Build Navigation Title table for the tracks. */
918 VCDTitles( p_access );
920 /* Add into the above entry points as "Chapters". */
921 if( ! VCDEntryPoints( p_access ) )
923 msg_Warn( p_access, "could not read entry points, will not use them" );
924 p_vcdplayer->b_valid_ep = false;
927 /* Initialize LID info and add that as a menu item */
928 if( ! VCDLIDs( p_access ) )
930 msg_Warn( p_access, "could not read entry LIDs" );
933 /* Do we set PBC (via LID) on? */
935 ( VCDINFO_ITEM_TYPE_LID == itemid.type
936 && p_vcdplayer->i_lids > itemid.num )
938 : VCDINFO_INVALID_ENTRY;
940 /* Initialize segment information and add that a "Track". */
941 VCDSegments( p_access );
943 vcdplayer_play( p_access, itemid );
945 free( p_access->psz_demux );
946 p_access->psz_demux = strdup( "ps" );
949 if( play_single_item )
950 VCDFixupPlayList(p_access,p_vcd,psz_source,&itemid,play_single_item);
953 p_vcdplayer->p_access = p_access;
959 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
961 free( p_vcdplayer->psz_source );
966 /*****************************************************************************
967 * VCDClose: closes VCD releasing allocated memory.
968 *****************************************************************************/
970 VCDClose ( vlc_object_t *p_this )
972 access_t *p_access = (access_t *)p_this;
973 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
975 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
979 for (i=0 ; i<p_vcdplayer->i_titles; i++)
980 if (p_vcdplayer->p_title[i])
981 free(p_vcdplayer->p_title[i]->psz_name);
984 vcdinfo_close( p_vcdplayer->vcd );
986 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
988 FREENULL( p_vcdplayer->p_entries );
989 FREENULL( p_vcdplayer->p_segments );
990 FREENULL( p_vcdplayer->psz_source );
991 FREENULL( p_vcdplayer->track );
992 FREENULL( p_vcdplayer->segment );
993 FREENULL( p_vcdplayer->entry );
994 FREENULL( p_access->psz_demux );
995 FREENULL( p_vcdplayer );
999 /*****************************************************************************
1000 * Control: The front-end or vlc engine calls here to ether get
1001 * information such as meta information or plugin capabilities or to
1002 * issue miscellaneous "set" requests.
1003 *****************************************************************************/
1004 static int VCDControl( access_t *p_access, int i_query, va_list args )
1006 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1010 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1011 "query %d", i_query );
1015 /* Pass back a copy of meta information that was gathered when we
1016 during the Open/Initialize call.
1018 case ACCESS_GET_META:
1019 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1021 if( p_vcdplayer->p_meta )
1023 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg(args,vlc_meta_t**);
1025 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1026 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1030 msg_Warn( p_access, "tried to copy NULL meta info" );
1034 case ACCESS_CAN_SEEK:
1035 case ACCESS_CAN_FASTSEEK:
1036 case ACCESS_CAN_PAUSE:
1037 case ACCESS_CAN_CONTROL_PACE:
1039 dbg_print( INPUT_DBG_EVENT,
1040 "seek/fastseek/pause/can_control_pace" );
1041 *((bool*)va_arg( args, bool* )) = true;
1045 case ACCESS_GET_PTS_DELAY:
1046 *(int64_t*)va_arg(args,int64_t *) = INT64_C(1000) *
1047 var_InheritInteger( p_access, "disc-caching" );
1051 case ACCESS_SET_PAUSE_STATE:
1054 case ACCESS_GET_TITLE_INFO:
1056 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1057 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1058 input_title_t ***ppp_title
1059 = (input_title_t***)va_arg( args, input_title_t*** );
1060 char *psz_mrl = malloc( psz_mrl_max );
1063 pi_int = (int*)va_arg( args, int* );
1065 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1066 p_vcdplayer->i_titles );
1070 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1071 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1072 VCDMetaInfo( p_access, psz_mrl );
1076 /* Duplicate title info */
1077 if( p_vcdplayer->i_titles == 0 )
1079 *pi_int = 0; ppp_title = NULL;
1082 *pi_int = p_vcdplayer->i_titles;
1083 *ppp_title = malloc(sizeof(input_title_t **)*p_vcdplayer->i_titles);
1085 if (!*ppp_title) return VLC_ENOMEM;
1087 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1088 if( p_vcdplayer->p_title[i] )
1090 vlc_input_title_Duplicate(p_vcdplayer->p_title[i]);
1094 case ACCESS_SET_TITLE:
1095 i = (int)va_arg( args, int );
1097 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1098 if( i != p_access->info.i_title )
1100 vcdinfo_itemid_t itemid;
1101 track_t i_track = i+1;
1102 unsigned int i_entry =
1103 vcdinfo_track_get_entry(p_vcdplayer->vcd,i_track);
1105 if( i < p_vcdplayer->i_tracks )
1107 /* FIXME! For now we are assuming titles are only
1108 tracks and that track == title+1 */
1109 itemid.num = i_track;
1110 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1114 /* FIXME! i_tracks+2 are Segments, but we need to be able
1115 to figure out which segment of that. i_tracks+1 is
1116 either Segments (if no LIDs) or LIDs otherwise. Again
1117 need a way to get the LID number. */
1119 msg_Warn(p_access,"Trying to set track (%u) beyond end "
1120 "of last track (%u).",i+1,p_vcdplayer->i_tracks);
1121 return VLC_EGENERIC;
1124 VCDSetOrigin(p_access,
1125 vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i_entry),
1130 case ACCESS_SET_SEEKPOINT:
1132 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1133 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1135 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1136 if( t->i_seekpoint > 0 )
1138 track_t i_track = p_access->info.i_title+1;
1141 /* FIXME! For now we are assuming titles are only tracks and
1142 that track == title+1 and we the play item is entries (not
1143 tracks or lids). We need to generalize all of this.
1146 if (i < p_vcdplayer->i_entries)
1148 p_vcdplayer->play_item.num = i;
1149 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1150 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1151 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1153 p_vcdplayer->play_item.num = i = i - p_vcdplayer->i_entries;
1154 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1158 p_vcdplayer->play_item.num = i
1159 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1160 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1161 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1164 VCDSetOrigin(p_access,vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i),
1165 i_track,&(p_vcdplayer->play_item));
1170 case ACCESS_SET_PRIVATE_ID_STATE:
1171 dbg_print( INPUT_DBG_EVENT, "set private id" );
1172 return VLC_EGENERIC;
1175 msg_Warn( p_access, "unimplemented query in control" );
1176 return VLC_EGENERIC;