1 /*****************************************************************************
2 * vcd.c : VCD input module for vlc using libcdio, libvcd and libvcdinfo.
3 * vlc-specific things tend to go here.
4 *****************************************************************************
5 * Copyright (C) 2000, 2003, 2004, 2005 the VideoLAN team
8 * Authors: Rocky Bernstein <rocky@panix.com>
9 * Some code is based on the non-libcdio VCD plugin (as there really
10 * isn't real developer documentation yet on how to write a
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 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_New( p_access, 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_SIZE
719 |INPUT_UPDATE_SEEKPOINT;
721 VCDUpdateTitle( p_access );
725 /*****************************************************************************
726 * vcd_Open: Opens a VCD device or file initializes, a list of
727 tracks, segements and entry lsns and sizes and returns an opaque handle.
728 *****************************************************************************/
729 static vcdinfo_obj_t *
730 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
732 access_t *p_access = (access_t *)p_this;
733 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
734 vcdinfo_obj_t *p_vcdobj;
738 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
740 if( !psz_dev ) return NULL;
742 actual_dev= ToLocaleDup(psz_dev);
743 if( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
752 Save summary info on tracks, segments and entries...
755 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) )
757 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
758 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
760 for (i=0; i<p_vcdplayer->i_tracks; i++)
762 unsigned int track_num=i+1;
763 p_vcdplayer->track[i].size =
764 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
765 p_vcdplayer->track[i].start_LSN =
766 vcdinfo_get_track_lsn(p_vcdobj, track_num);
769 p_vcdplayer->track = NULL;
771 if( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) )
773 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
774 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
776 for (i=0; i<p_vcdplayer->i_entries; i++)
778 p_vcdplayer->entry[i].size =
779 vcdinfo_get_entry_sect_count(p_vcdobj, i);
780 p_vcdplayer->entry[i].start_LSN =
781 vcdinfo_get_entry_lsn(p_vcdobj, i);
784 p_vcdplayer->entry = NULL;
786 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) )
788 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
789 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
791 for (i=0; i<p_vcdplayer->i_segments; i++)
793 p_vcdplayer->segment[i].size =
794 vcdinfo_get_seg_sector_count(p_vcdobj, i);
795 p_vcdplayer->segment[i].start_LSN =
796 vcdinfo_get_seg_lsn(p_vcdobj, i);
799 p_vcdplayer->segment = NULL;
804 /****************************************************************************
805 Update the "varname" variable to i_num without triggering a callback.
806 ****************************************************************************/
808 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
809 const char *p_varname, char *p_label,
810 const char *p_debug_label)
816 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
817 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
822 text.psz_string = p_label;
823 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
825 var_Change( p_access, p_varname, i_action, &val, NULL );
829 /*****************************************************************************
831 *****************************************************************************/
833 /*****************************************************************************
835 read in meta-information about VCD: the number of tracks, segments,
836 entries, size and starting information. Then set up state variables so
837 that we read/seek starting at the location specified.
839 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
840 and VLC_EGENERIC for some other error.
841 *****************************************************************************/
843 VCDOpen ( vlc_object_t *p_this )
845 access_t *p_access = (access_t *)p_this;
846 vcdplayer_t *p_vcdplayer;
848 vcdinfo_itemid_t itemid;
849 bool play_single_item = false;
851 p_access->pf_read = NULL;
852 p_access->pf_block = VCDReadBlock;
853 p_access->pf_control = VCDControl;
854 p_access->pf_seek = VCDSeek;
856 p_access->info.i_update = 0;
857 p_access->info.i_size = 0;
858 p_access->info.i_pos = 0;
859 p_access->info.b_eof = false;
860 p_access->info.i_title = 0;
861 p_access->info.i_seekpoint = 0;
863 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
865 if( p_vcdplayer == NULL )
868 p_vcdplayer->i_debug = var_InheritInteger( p_this, MODULE_STRING "-debug" );
869 p_access->p_sys = (access_sys_t *) p_vcdplayer;
871 /* Set where to log errors messages from libcdio. */
872 p_vcd_access = p_access;
873 cdio_log_set_handler ( cdio_log_handler );
874 vcd_log_set_handler ( vcd_log_handler );
876 psz_source = VCDParse( p_access, &itemid, &play_single_item );
878 if ( NULL == psz_source )
881 return( VLC_EGENERIC );
884 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
885 psz_source, p_access->psz_location );
887 p_vcdplayer->psz_source = strdup(psz_source);
888 p_vcdplayer->i_blocks_per_read = var_InheritInteger( p_this, MODULE_STRING
889 "-blocks-per-read" );
890 p_vcdplayer->b_track_length = var_InheritInteger( p_this, MODULE_STRING
892 p_vcdplayer->in_still = false;
893 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
894 p_vcdplayer->p_input = access_GetParentInput( p_access );
895 // p_vcdplayer->p_meta = vlc_meta_New();
896 p_vcdplayer->p_segments = NULL;
897 p_vcdplayer->p_entries = NULL;
901 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
906 p_vcdplayer->b_svd = vcdinfo_get_tracksSVD(p_vcdplayer->vcd);
908 /* Get track information. */
909 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
911 if( p_vcdplayer->i_tracks<1 || CDIO_INVALID_TRACK==p_vcdplayer->i_tracks )
913 vcdinfo_close( p_vcdplayer->vcd );
914 LOG_ERR ("no movie tracks found" );
918 /* Build Navigation Title table for the tracks. */
919 VCDTitles( p_access );
921 /* Add into the above entry points as "Chapters". */
922 if( ! VCDEntryPoints( p_access ) )
924 msg_Warn( p_access, "could not read entry points, will not use them" );
925 p_vcdplayer->b_valid_ep = false;
928 /* Initialize LID info and add that as a menu item */
929 if( ! VCDLIDs( p_access ) )
931 msg_Warn( p_access, "could not read entry LIDs" );
934 /* Do we set PBC (via LID) on? */
936 ( VCDINFO_ITEM_TYPE_LID == itemid.type
937 && p_vcdplayer->i_lids > itemid.num )
939 : VCDINFO_INVALID_ENTRY;
941 /* Initialize segment information and add that a "Track". */
942 VCDSegments( p_access );
944 vcdplayer_play( p_access, itemid );
946 free( p_access->psz_demux );
947 p_access->psz_demux = strdup( "ps" );
950 if( play_single_item )
951 VCDFixupPlayList(p_access,p_vcd,psz_source,&itemid,play_single_item);
954 p_vcdplayer->p_access = p_access;
960 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
962 free( p_vcdplayer->psz_source );
967 /*****************************************************************************
968 * VCDClose: closes VCD releasing allocated memory.
969 *****************************************************************************/
971 VCDClose ( vlc_object_t *p_this )
973 access_t *p_access = (access_t *)p_this;
974 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
976 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
980 for (i=0 ; i<p_vcdplayer->i_titles; i++)
981 if (p_vcdplayer->p_title[i])
982 free(p_vcdplayer->p_title[i]->psz_name);
985 vcdinfo_close( p_vcdplayer->vcd );
987 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
989 FREENULL( p_vcdplayer->p_entries );
990 FREENULL( p_vcdplayer->p_segments );
991 FREENULL( p_vcdplayer->psz_source );
992 FREENULL( p_vcdplayer->track );
993 FREENULL( p_vcdplayer->segment );
994 FREENULL( p_vcdplayer->entry );
995 FREENULL( p_access->psz_demux );
996 FREENULL( p_vcdplayer );
1000 /*****************************************************************************
1001 * Control: The front-end or vlc engine calls here to ether get
1002 * information such as meta information or plugin capabilities or to
1003 * issue miscellaneous "set" requests.
1004 *****************************************************************************/
1005 static int VCDControl( access_t *p_access, int i_query, va_list args )
1007 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1011 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1012 "query %d", i_query );
1016 /* Pass back a copy of meta information that was gathered when we
1017 during the Open/Initialize call.
1019 case ACCESS_GET_META:
1020 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1022 if( p_vcdplayer->p_meta )
1024 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg(args,vlc_meta_t**);
1026 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1027 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1031 msg_Warn( p_access, "tried to copy NULL meta info" );
1035 case ACCESS_CAN_SEEK:
1036 case ACCESS_CAN_FASTSEEK:
1037 case ACCESS_CAN_PAUSE:
1038 case ACCESS_CAN_CONTROL_PACE:
1040 dbg_print( INPUT_DBG_EVENT,
1041 "seek/fastseek/pause/can_control_pace" );
1042 *((bool*)va_arg( args, bool* )) = true;
1046 case ACCESS_GET_PTS_DELAY:
1047 *(int64_t*)va_arg(args,int64_t *) = INT64_C(1000) *
1048 var_InheritInteger( p_access, "disc-caching" );
1049 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1053 case ACCESS_SET_PAUSE_STATE:
1054 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1057 case ACCESS_GET_TITLE_INFO:
1059 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1060 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1061 input_title_t ***ppp_title
1062 = (input_title_t***)va_arg( args, input_title_t*** );
1063 char *psz_mrl = malloc( psz_mrl_max );
1066 pi_int = (int*)va_arg( args, int* );
1068 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1069 p_vcdplayer->i_titles );
1073 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1074 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1075 VCDMetaInfo( p_access, psz_mrl );
1079 /* Duplicate title info */
1080 if( p_vcdplayer->i_titles == 0 )
1082 *pi_int = 0; ppp_title = NULL;
1085 *pi_int = p_vcdplayer->i_titles;
1086 *ppp_title = malloc(sizeof(input_title_t **)*p_vcdplayer->i_titles);
1088 if (!*ppp_title) return VLC_ENOMEM;
1090 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1091 if( p_vcdplayer->p_title[i] )
1093 vlc_input_title_Duplicate(p_vcdplayer->p_title[i]);
1097 case ACCESS_SET_TITLE:
1098 i = (int)va_arg( args, int );
1100 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1101 if( i != p_access->info.i_title )
1103 vcdinfo_itemid_t itemid;
1104 track_t i_track = i+1;
1105 unsigned int i_entry =
1106 vcdinfo_track_get_entry(p_vcdplayer->vcd,i_track);
1108 if( i < p_vcdplayer->i_tracks )
1110 /* FIXME! For now we are assuming titles are only
1111 tracks and that track == title+1 */
1112 itemid.num = i_track;
1113 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1117 /* FIXME! i_tracks+2 are Segments, but we need to be able
1118 to figure out which segment of that. i_tracks+1 is
1119 either Segments (if no LIDs) or LIDs otherwise. Again
1120 need a way to get the LID number. */
1122 msg_Warn(p_access,"Trying to set track (%u) beyond end "
1123 "of last track (%u).",i+1,p_vcdplayer->i_tracks);
1124 return VLC_EGENERIC;
1127 VCDSetOrigin(p_access,
1128 vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i_entry),
1133 case ACCESS_SET_SEEKPOINT:
1135 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1136 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1138 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1139 if( t->i_seekpoint > 0 )
1141 track_t i_track = p_access->info.i_title+1;
1144 /* FIXME! For now we are assuming titles are only tracks and
1145 that track == title+1 and we the play item is entries (not
1146 tracks or lids). We need to generalize all of this.
1149 if (i < p_vcdplayer->i_entries)
1151 p_vcdplayer->play_item.num = i;
1152 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1153 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1154 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1156 p_vcdplayer->play_item.num = i = i - p_vcdplayer->i_entries;
1157 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1161 p_vcdplayer->play_item.num = i
1162 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1163 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1164 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1167 VCDSetOrigin(p_access,vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i),
1168 i_track,&(p_vcdplayer->play_item));
1173 case ACCESS_SET_PRIVATE_ID_STATE:
1174 dbg_print( INPUT_DBG_EVENT, "set private id" );
1175 return VLC_EGENERIC;
1178 msg_Warn( p_access, "unimplemented query in control" );
1179 return VLC_EGENERIC;