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_vcdplayer->i_cur_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( p_vcdplayer->i_cur_chapter != i_seekpoint )
301 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %d",
303 p_vcdplayer->i_cur_chapter = i_seekpoint;
305 p_access->info.b_eof = false;
309 /*****************************************************************************
310 VCDEntryPoints: Reads the information about the entry points on the disc
311 and initializes area information with that.
312 Before calling this track information should have been read in.
313 *****************************************************************************/
315 VCDEntryPoints( access_t * p_access )
317 if (!p_access || !p_access->p_sys) return false;
319 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
320 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdplayer->vcd);
321 const track_t i_last_track
322 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
323 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
326 if (0 == i_entries) {
327 LOG_ERR ("no entires found -- something is wrong" );
331 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
333 if( p_vcdplayer->p_entries == NULL )
335 LOG_ERR ("not enough memory for entry points treatment" );
339 p_vcdplayer->i_entries = i_entries;
341 for( i = 0 ; i < i_entries ; i++ )
343 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
344 if( i_track <= i_last_track )
346 seekpoint_t *s = vlc_seekpoint_New();
349 snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i );
351 p_vcdplayer->p_entries[i] =
352 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
354 s->psz_name = strdup(psz_entry);
355 s->i_byte_offset = (p_vcdplayer->p_entries[i]
356 - vcdinfo_get_track_lsn(p_vcdplayer->vcd,i_track))
359 dbg_print( INPUT_DBG_MRL, "%s, lsn %d, byte_offset %"PRId64"",
360 s->psz_name, p_vcdplayer->p_entries[i],
362 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
363 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
366 msg_Warn( p_access, "wrong track number found in entry points" );
368 p_vcdplayer->b_valid_ep = true;
372 /*****************************************************************************
373 * VCDSegments: Reads the information about the segments the disc.
374 *****************************************************************************/
376 VCDSegments( access_t * p_access )
378 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
382 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
384 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
385 "Segments: %d", p_vcdplayer->i_segments);
387 if ( 0 == p_vcdplayer->i_segments ) return false;
389 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
390 p_vcdplayer->i_titles++;
392 t->i_size = 0; /* Not sure Segments have a size associated */
393 t->psz_name = strdup(_("Segments"));
395 /* We have one additional segment allocated so we can get the size
396 by subtracting seg[i+1] - seg[i].
398 p_vcdplayer->p_segments=malloc(sizeof(lsn_t)*(p_vcdplayer->i_segments+1));
399 if( p_vcdplayer->p_segments == NULL )
401 LOG_ERR ("not enough memory for segment treatment" );
405 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
407 char psz_segment[100];
408 seekpoint_t *s = vlc_seekpoint_New();
409 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
411 snprintf( psz_segment, sizeof(psz_segment), "%s %02d", _("Segment"),
414 s->i_byte_offset = 0; /* Not sure what this would mean here */
415 s->psz_name = strdup(psz_segment);
416 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
419 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
420 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
421 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
422 p_vcdplayer->i_segments-1);
427 /*****************************************************************************
428 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
430 We start area addressing for tracks at 1 since the default area 0
431 is reserved for segments.
432 *****************************************************************************/
434 VCDTitles( access_t * p_access )
436 /* We'll assume a VCD has its first MPEG track
437 cdio_get_first_track_num()+1 could be used if one wanted to be
438 very careful about this. Note: cdio_get_first_track() will give the
439 ISO-9660 track before the MPEG tracks.
442 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
445 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
448 p_vcdplayer->i_titles = 0;
449 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
451 input_title_t *t = p_vcdplayer->p_title[i-1] =
452 vlc_input_title_New();
455 snprintf( psz_track, sizeof(psz_track), "%s %02d", _("Track"), i );
456 t->i_size = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
457 i ) * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
458 t->psz_name = strdup(psz_track);
460 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %"PRIi64, i, t->i_size );
462 p_vcdplayer->i_titles++;
469 /*****************************************************************************
470 VCDLIDs: Reads the LIST IDs from the LOT.
471 *****************************************************************************/
473 VCDLIDs( access_t * p_access )
475 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
477 unsigned int i_lid, i_title;
479 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
480 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
482 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
483 "LIDs: %d", p_vcdplayer->i_lids);
485 if ( 0 == p_vcdplayer->i_lids ) return false;
487 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
489 vcdinfo_visit_lot (p_vcdplayer->vcd, false);
493 We need to change libvcdinfo to be more robust when there are
494 problems reading the extended PSD. Given that area-highlighting and
495 selection features in the extended PSD haven't been implemented,
496 it's best then to not try to read this at all.
498 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
499 vcdinfo_visit_lot (p_vcdplayer->vcd, true);
503 /* Set up LIDs Navigation Menu */
504 t = vlc_input_title_New();
506 t->psz_name = strdup( "LIDs" );
508 i_title = p_vcdplayer->i_tracks;
509 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
512 seekpoint_t *s = vlc_seekpoint_New();
514 snprintf( psz_lid, sizeof(psz_lid), "%s %02d", _("LID"), i_lid );
516 s->i_byte_offset = 0; /* A lid doesn't have an offset
517 size associated with it */
518 s->psz_name = strdup(psz_lid);
519 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
522 #ifdef DYNAMICALLY_ALLOCATED
523 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
525 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
526 p_vcdplayer->i_titles++;
532 /*****************************************************************************
533 * VCDParse: parse command line
534 *****************************************************************************/
536 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
537 /*out*/ bool *play_single_item )
539 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
544 if( var_InheritBool( p_access, MODULE_STRING "-PBC" ) ) {
545 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
547 *play_single_item = false;
551 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
556 /* On Win32 we want the VCD access plugin to be explicitly requested,
557 * we end up with lots of problems otherwise */
558 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
561 if( !p_access->psz_location )
566 psz_parser = psz_source = strdup( p_access->psz_location );
568 /* Parse input string :
569 * [device][@[type][title]] */
570 while( *psz_parser && *psz_parser != '@' )
575 if( *psz_parser == '@' )
577 /* Found the divide between the source name and the
578 type+entry number. */
584 switch(*psz_parser) {
586 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
588 *play_single_item = true;
591 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
593 *play_single_item = false;
596 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
598 *play_single_item = true;
601 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
603 *play_single_item = true;
609 num = strtol( psz_parser, &psz_next, 10 );
610 if ( *psz_parser != '\0' && *psz_next == '\0')
616 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
623 /* No source specified, so figure it out. */
624 if( !p_access->psz_access ) return NULL;
626 psz_source = var_InheritString( p_access, "vcd" );
630 /* Scan for a CD-ROM drive with a VCD in it. */
631 char **cd_drives = cdio_get_devices_with_cap(NULL,
632 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
633 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
635 if( NULL == cd_drives ) return NULL;
636 if( cd_drives[0] == NULL )
638 cdio_free_device_list( cd_drives );
641 psz_source = strdup( cd_drives[0] );
642 cdio_free_device_list( cd_drives );
646 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
647 "source=%s entry=%d type=%d",
648 psz_source, p_itemid->num, p_itemid->type);
654 Sets start origin for subsequent seeks/reads
657 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
658 const vcdinfo_itemid_t *p_itemid )
660 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
662 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
663 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn, i_track );
665 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
667 switch (p_vcdplayer->play_item.type)
669 case VCDINFO_ITEM_TYPE_ENTRY:
670 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
671 "chapter", _("Entry"), "Setting entry/segment");
672 p_vcdplayer->i_cur_title = i_track - 1;
673 if (p_vcdplayer->b_track_length)
675 p_vcdplayer->size = p_vcdplayer->p_title[i_track-1]->i_size;
676 p_access->info.i_pos = (uint64_t) M2F2_SECTOR_SIZE *
677 (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track)-i_lsn);
679 p_vcdplayer->size = M2F2_SECTOR_SIZE * (int64_t)
680 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd,p_itemid->num);
681 p_access->info.i_pos = 0;
683 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %"PRIu64", pos: %"PRIu64,
684 p_vcdplayer->size, p_access->info.i_pos );
685 p_vcdplayer->i_cur_chapter = p_itemid->num;
688 case VCDINFO_ITEM_TYPE_SEGMENT:
689 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
690 "chapter", _("Segment"), "Setting entry/segment");
691 /* The last title entry is the for segments (when segments exist
692 and they must here. The segment seekpoints are stored after
693 the entry seekpoints and (zeroed) lid seekpoints.
695 p_vcdplayer->i_cur_title = p_vcdplayer->i_titles - 1;
696 p_vcdplayer->size = 0; /* No seeking on stills, please. */
697 p_access->info.i_pos = 0;
698 p_vcdplayer->i_cur_chapter = p_vcdplayer->i_entries
699 + p_vcdplayer->i_lids + p_itemid->num;
702 case VCDINFO_ITEM_TYPE_TRACK:
703 p_vcdplayer->i_cur_title = i_track - 1;
704 p_vcdplayer->size = p_vcdplayer->p_title[i_track - 1]->i_size;
705 p_access->info.i_pos = 0;
706 p_vcdplayer->i_cur_chapter = vcdinfo_track_get_entry(p_vcdplayer->vcd,
711 msg_Warn( p_access, "can't set origin for play type %d",
712 p_vcdplayer->play_item.type );
715 VCDUpdateTitle( p_access );
719 /*****************************************************************************
720 * vcd_Open: Opens a VCD device or file initializes, a list of
721 tracks, segements and entry lsns and sizes and returns an opaque handle.
722 *****************************************************************************/
723 static vcdinfo_obj_t *
724 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
726 access_t *p_access = (access_t *)p_this;
727 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
728 vcdinfo_obj_t *p_vcdobj;
732 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
734 if( !psz_dev ) return NULL;
736 actual_dev= ToLocaleDup(psz_dev);
737 if( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
746 Save summary info on tracks, segments and entries...
749 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) )
751 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
752 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
754 for (i=0; i<p_vcdplayer->i_tracks; i++)
756 unsigned int track_num=i+1;
757 p_vcdplayer->track[i].size =
758 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
759 p_vcdplayer->track[i].start_LSN =
760 vcdinfo_get_track_lsn(p_vcdobj, track_num);
763 p_vcdplayer->track = NULL;
765 if( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) )
767 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
768 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
770 for (i=0; i<p_vcdplayer->i_entries; i++)
772 p_vcdplayer->entry[i].size =
773 vcdinfo_get_entry_sect_count(p_vcdobj, i);
774 p_vcdplayer->entry[i].start_LSN =
775 vcdinfo_get_entry_lsn(p_vcdobj, i);
778 p_vcdplayer->entry = NULL;
780 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) )
782 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
783 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
785 for (i=0; i<p_vcdplayer->i_segments; i++)
787 p_vcdplayer->segment[i].size =
788 vcdinfo_get_seg_sector_count(p_vcdobj, i);
789 p_vcdplayer->segment[i].start_LSN =
790 vcdinfo_get_seg_lsn(p_vcdobj, i);
793 p_vcdplayer->segment = NULL;
798 /****************************************************************************
799 Update the "varname" variable to i_num without triggering a callback.
800 ****************************************************************************/
802 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
803 const char *p_varname, char *p_label,
804 const char *p_debug_label)
810 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
811 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
816 text.psz_string = p_label;
817 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
819 var_Change( p_access, p_varname, i_action, &val, NULL );
823 /*****************************************************************************
825 *****************************************************************************/
827 /*****************************************************************************
829 read in meta-information about VCD: the number of tracks, segments,
830 entries, size and starting information. Then set up state variables so
831 that we read/seek starting at the location specified.
833 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
834 and VLC_EGENERIC for some other error.
835 *****************************************************************************/
837 VCDOpen ( vlc_object_t *p_this )
839 access_t *p_access = (access_t *)p_this;
840 vcdplayer_t *p_vcdplayer;
842 vcdinfo_itemid_t itemid;
843 bool play_single_item = false;
845 p_access->pf_read = NULL;
846 p_access->pf_block = VCDReadBlock;
847 p_access->pf_control = VCDControl;
848 p_access->pf_seek = VCDSeek;
850 p_access->info.i_pos = 0;
851 p_access->info.b_eof = false;
853 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
855 if( p_vcdplayer == NULL )
858 p_vcdplayer->i_debug = var_InheritInteger( p_this, MODULE_STRING "-debug" );
859 p_access->p_sys = (access_sys_t *) p_vcdplayer;
860 p_vcdplayer->size = 0;
862 /* Set where to log errors messages from libcdio. */
863 p_vcd_access = p_access;
864 cdio_log_set_handler ( cdio_log_handler );
865 vcd_log_set_handler ( vcd_log_handler );
867 psz_source = VCDParse( p_access, &itemid, &play_single_item );
869 if ( NULL == psz_source )
872 return( VLC_EGENERIC );
875 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
876 psz_source, p_access->psz_location );
878 p_vcdplayer->psz_source = strdup(psz_source);
879 p_vcdplayer->i_blocks_per_read = var_InheritInteger( p_this, MODULE_STRING
880 "-blocks-per-read" );
881 p_vcdplayer->b_track_length = var_InheritInteger( p_this, MODULE_STRING
883 p_vcdplayer->in_still = false;
884 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
885 p_vcdplayer->p_input = access_GetParentInput( p_access );
886 // p_vcdplayer->p_meta = vlc_meta_New();
887 p_vcdplayer->p_segments = NULL;
888 p_vcdplayer->p_entries = NULL;
889 p_vcdplayer->i_cur_title = 0;
890 p_vcdplayer->i_cur_chapter = 0;
894 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
899 p_vcdplayer->b_svd = vcdinfo_get_tracksSVD(p_vcdplayer->vcd);
901 /* Get track information. */
902 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
904 if( p_vcdplayer->i_tracks<1 || CDIO_INVALID_TRACK==p_vcdplayer->i_tracks )
906 vcdinfo_close( p_vcdplayer->vcd );
907 LOG_ERR ("no movie tracks found" );
911 /* Build Navigation Title table for the tracks. */
912 VCDTitles( p_access );
914 /* Add into the above entry points as "Chapters". */
915 if( ! VCDEntryPoints( p_access ) )
917 msg_Warn( p_access, "could not read entry points, will not use them" );
918 p_vcdplayer->b_valid_ep = false;
921 /* Initialize LID info and add that as a menu item */
922 if( ! VCDLIDs( p_access ) )
924 msg_Warn( p_access, "could not read entry LIDs" );
927 /* Do we set PBC (via LID) on? */
929 ( VCDINFO_ITEM_TYPE_LID == itemid.type
930 && p_vcdplayer->i_lids > itemid.num )
932 : VCDINFO_INVALID_ENTRY;
934 /* Initialize segment information and add that a "Track". */
935 VCDSegments( p_access );
937 vcdplayer_play( p_access, itemid );
939 free( p_access->psz_demux );
940 p_access->psz_demux = strdup( "ps" );
943 if( play_single_item )
944 VCDFixupPlayList(p_access,p_vcd,psz_source,&itemid,play_single_item);
947 p_vcdplayer->p_access = p_access;
953 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
955 free( p_vcdplayer->psz_source );
960 /*****************************************************************************
961 * VCDClose: closes VCD releasing allocated memory.
962 *****************************************************************************/
964 VCDClose ( vlc_object_t *p_this )
966 access_t *p_access = (access_t *)p_this;
967 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
969 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
973 for (i=0 ; i<p_vcdplayer->i_titles; i++)
974 if (p_vcdplayer->p_title[i])
975 free(p_vcdplayer->p_title[i]->psz_name);
978 vcdinfo_close( p_vcdplayer->vcd );
980 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
982 FREENULL( p_vcdplayer->p_entries );
983 FREENULL( p_vcdplayer->p_segments );
984 FREENULL( p_vcdplayer->psz_source );
985 FREENULL( p_vcdplayer->track );
986 FREENULL( p_vcdplayer->segment );
987 FREENULL( p_vcdplayer->entry );
988 FREENULL( p_access->psz_demux );
989 FREENULL( p_vcdplayer );
993 /*****************************************************************************
994 * Control: The front-end or vlc engine calls here to ether get
995 * information such as meta information or plugin capabilities or to
996 * issue miscellaneous "set" requests.
997 *****************************************************************************/
998 static int VCDControl( access_t *p_access, int i_query, va_list args )
1000 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1004 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1005 "query %d", i_query );
1010 /* Pass back a copy of meta information that was gathered when we
1011 during the Open/Initialize call.
1013 case ACCESS_GET_META:
1014 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1015 if( p_vcdplayer->p_meta )
1017 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg(args,vlc_meta_t**);
1019 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1020 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1023 msg_Warn( p_access, "tried to copy NULL meta info" );
1026 case ACCESS_CAN_SEEK:
1027 case ACCESS_CAN_FASTSEEK:
1028 case ACCESS_CAN_PAUSE:
1029 case ACCESS_CAN_CONTROL_PACE:
1030 dbg_print( INPUT_DBG_EVENT,
1031 "seek/fastseek/pause/can_control_pace" );
1032 *((bool*)va_arg( args, bool* )) = true;
1035 case ACCESS_GET_PTS_DELAY:
1036 *(int64_t*)va_arg(args,int64_t *) = INT64_C(1000) *
1037 var_InheritInteger( p_access, "disc-caching" );
1040 case ACCESS_SET_PAUSE_STATE:
1043 case ACCESS_GET_TITLE_INFO:
1045 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1046 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1047 input_title_t ***ppp_title
1048 = (input_title_t***)va_arg( args, input_title_t*** );
1049 char *psz_mrl = malloc( psz_mrl_max );
1052 pi_int = (int*)va_arg( args, int* );
1054 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1055 p_vcdplayer->i_titles );
1059 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1060 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1061 VCDMetaInfo( p_access, psz_mrl );
1065 /* Duplicate title info */
1066 if( p_vcdplayer->i_titles == 0 )
1068 *pi_int = 0; ppp_title = NULL;
1071 *pi_int = p_vcdplayer->i_titles;
1072 *ppp_title = malloc(sizeof(input_title_t **)*p_vcdplayer->i_titles);
1074 if (!*ppp_title) return VLC_ENOMEM;
1076 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1077 if( p_vcdplayer->p_title[i] )
1079 vlc_input_title_Duplicate(p_vcdplayer->p_title[i]);
1083 case ACCESS_GET_TITLE:
1084 *va_arg( args, unsigned * ) = p_vcdplayer->i_cur_title;
1087 case ACCESS_GET_SEEKPOINT:
1088 *va_arg( args, unsigned * ) = p_vcdplayer->i_cur_chapter;
1091 case ACCESS_SET_TITLE:
1092 i = (int)va_arg( args, int );
1094 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1095 if( i != p_vcdplayer->i_cur_title )
1097 vcdinfo_itemid_t itemid;
1098 track_t i_track = i+1;
1099 unsigned int i_entry =
1100 vcdinfo_track_get_entry(p_vcdplayer->vcd,i_track);
1102 if( i < p_vcdplayer->i_tracks )
1104 /* FIXME! For now we are assuming titles are only
1105 tracks and that track == title+1 */
1106 itemid.num = i_track;
1107 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1111 /* FIXME! i_tracks+2 are Segments, but we need to be able
1112 to figure out which segment of that. i_tracks+1 is
1113 either Segments (if no LIDs) or LIDs otherwise. Again
1114 need a way to get the LID number. */
1116 msg_Warn(p_access,"Trying to set track (%u) beyond end "
1117 "of last track (%u).",i+1,p_vcdplayer->i_tracks);
1118 return VLC_EGENERIC;
1121 VCDSetOrigin(p_access,
1122 vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i_entry),
1127 case ACCESS_SET_SEEKPOINT:
1129 input_title_t *t = p_vcdplayer->p_title[p_vcdplayer->i_cur_title];
1130 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1132 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1133 if( t->i_seekpoint > 0 )
1135 track_t i_track = p_vcdplayer->i_cur_title + 1;
1138 /* FIXME! For now we are assuming titles are only tracks and
1139 that track == title+1 and we the play item is entries (not
1140 tracks or lids). We need to generalize all of this.
1143 if (i < p_vcdplayer->i_entries)
1145 p_vcdplayer->play_item.num = i;
1146 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1147 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1148 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1150 p_vcdplayer->play_item.num = i = i - p_vcdplayer->i_entries;
1151 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1155 p_vcdplayer->play_item.num = i
1156 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1157 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1158 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1161 VCDSetOrigin(p_access,vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i),
1162 i_track,&(p_vcdplayer->play_item));
1168 return VLC_EGENERIC;