1 /*****************************************************************************
2 * vcd.c : VCD input module for vlc using libcdio, libvcd and libvcdinfo.
3 * vlc-specific things tend to go here.
4 *****************************************************************************
5 * Copyright (C) 2000, 2003, 2004 VideoLAN
8 * Authors: Rocky Bernstein <rocky@panix.com>
9 * Some code is based on the non-libcdio VCD plugin (as there really
10 * isn't real developer documentation yet on how to write a
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
34 #include <vlc/input.h>
41 #include <cdio/cdio.h>
42 #include <cdio/cd_types.h>
43 #include <cdio/logging.h>
44 #include <cdio/util.h>
45 #include <libvcd/info.h>
46 #include <libvcd/logging.h>
48 #define FREE_AND_NULL(ptr) if (NULL != ptr) free(ptr); ptr = NULL;
50 extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
51 const vcdinfo_itemid_t *p_itemid );
53 /*****************************************************************************
55 *****************************************************************************/
57 /* First those which are accessed from outside (via pointers). */
58 static block_t *VCDReadBlock ( access_t * );
60 static int VCDControl ( access_t *p_access, int i_query,
63 /* Now those which are strictly internal */
64 static vlc_bool_t VCDEntryPoints ( access_t * );
65 static vlc_bool_t VCDLIDs ( access_t * );
66 static vlc_bool_t VCDSegments ( access_t * );
67 static int VCDTitles ( access_t * );
68 static char *VCDParse ( access_t *,
69 /*out*/ vcdinfo_itemid_t * p_itemid ,
70 /*out*/ vlc_bool_t *play_single_item );
72 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
73 const char *p_varname, char *p_label,
74 const char *p_debug_label );
76 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
78 /****************************************************************************
80 ****************************************************************************/
82 /* FIXME: This variable is a hack. Would be nice to eliminate the
85 static access_t *p_vcd_access = NULL;
87 /* process messages that originate from libcdio. */
89 cdio_log_handler (cdio_log_level_t level, const char message[])
91 const vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
95 if (p_vcd->i_debug & INPUT_DBG_CDIO)
96 msg_Dbg( p_vcd_access, message);
99 msg_Warn( p_vcd_access, message);
102 case CDIO_LOG_ASSERT:
103 msg_Err( p_vcd_access, message);
106 msg_Warn( p_vcd_access, message,
107 _("The above message had unknown log level"),
113 /* process messages that originate from vcdinfo. */
115 vcd_log_handler (vcd_log_level_t level, const char message[])
117 vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
121 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
122 msg_Dbg( p_vcd_access, message);
125 msg_Warn( p_vcd_access, message);
129 msg_Err( p_vcd_access, message);
132 msg_Warn( p_vcd_access, "%s\n%s %d", message,
133 _("The above message had unknown vcdimager log level"),
139 /*****************************************************************************
140 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
141 NULL is returned if something went wrong.
142 *****************************************************************************/
144 VCDReadBlock( access_t * p_access )
146 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
148 const int i_blocks = p_vcd->i_blocks_per_read;
153 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
154 (long unsigned int) p_vcd->i_lsn );
156 /* Allocate a block for the reading */
157 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
159 msg_Err( p_access, "cannot get a new block of size: %i",
160 i_blocks * M2F2_SECTOR_SIZE );
161 block_Release( p_block );
165 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
167 const lsn_t old_lsn = p_vcd->i_lsn;
169 switch ( vcdplayer_read(p_access, (byte_t *) p_block->p_buffer
170 + (i_read*M2F2_SECTOR_SIZE)) ) {
172 /* End reached. Return NULL to indicated this. */
173 block_Release( p_block );
176 /* Some sort of error. Should we increment lsn? to skip block?
178 block_Release( p_block );
180 case READ_STILL_FRAME:
182 dbg_print(INPUT_DBG_STILL, "Handled still event\n");
183 /* Reached the end of a still frame. */
184 byte_t * p_buf = (byte_t *) p_block->p_buffer;
186 p_buf += (i_read*M2F2_SECTOR_SIZE);
187 memset(p_buf, 0, M2F2_SECTOR_SIZE);
190 dbg_print(INPUT_DBG_STILL, "Handled still event");
192 p_vcd->in_still = VLC_TRUE;
193 var_SetInteger( p_access, "state", PAUSE_S );
204 p_access->info.i_pos += (p_vcd->i_lsn - old_lsn) * M2F2_SECTOR_SIZE;
206 /* Update seekpoint */
207 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type )
209 unsigned int i_entry = p_vcd->play_item.num+1;
210 lsn_t i_lsn = vcdinfo_get_entry_lba(p_vcd->vcd, i_entry);
211 if (p_vcd->i_lsn >= i_lsn )
213 const track_t i_track = p_vcd->i_track;
214 p_vcd->play_item.num = i_entry;
215 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "entry change" );
216 VCDSetOrigin( p_access, i_lsn, i_track, &(p_vcd->play_item) );
225 /****************************************************************************
227 ****************************************************************************/
229 VCDSeek( access_t * p_access, int64_t i_pos )
231 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
234 vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
235 const input_title_t *t = p_vcd->p_title[p_access->info.i_title];
237 unsigned int i_entry=VCDINFO_INVALID_ENTRY;
239 /* Next sector to read */
240 p_access->info.i_pos = i_pos;
241 p_vcd->i_lsn = (i_pos / (int64_t)M2F2_SECTOR_SIZE) +
245 if( p_vcd->b_valid_ep )
247 for( i_entry = 0 ; i_entry < p_vcd->i_entries ; i_entry ++ )
249 if( p_vcd->i_lsn < p_vcd->p_entries[i_entry] )
251 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
252 "chapter", _("Entry"), "Setting entry" );
258 vcdinfo_itemid_t itemid;
259 itemid.num = i_entry;
260 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
261 VCDSetOrigin(p_access, p_vcd->i_lsn, p_vcd->i_track,
266 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
267 "orig %lu, cur: %lu, offset: %lld, entry %d",
268 (long unsigned int) p_vcd->origin_lsn,
269 (long unsigned int) p_vcd->i_lsn, i_pos,
273 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
275 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
276 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
279 /* Update current seekpoint */
280 if( i_seekpoint != p_access->info.i_seekpoint )
282 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
283 (long unsigned int) i_seekpoint );
284 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
285 p_access->info.i_seekpoint = i_seekpoint;
293 /*****************************************************************************
294 VCDEntryPoints: Reads the information about the entry points on the disc
295 and initializes area information with that.
296 Before calling this track information should have been read in.
297 *****************************************************************************/
299 VCDEntryPoints( access_t * p_access )
301 if (!p_access || !p_access->p_sys) return VLC_FALSE;
304 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
305 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcd->vcd);
306 const track_t i_last_track
307 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcd->vcd))
308 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcd->vcd));
311 if (0 == i_entries) {
312 LOG_ERR ("no entires found -- something is wrong" );
316 p_vcd->p_entries = malloc( sizeof( lsn_t ) * i_entries );
318 if( p_vcd->p_entries == NULL )
320 LOG_ERR ("not enough memory for entry points treatment" );
324 p_vcd->i_entries = i_entries;
326 for( i = 0 ; i < i_entries ; i++ )
328 const track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
329 if( i_track <= i_last_track ) {
330 seekpoint_t *s = vlc_seekpoint_New();
333 snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
335 p_vcd->p_entries[i] = vcdinfo_get_entry_lba(p_vcd->vcd, i);
337 s->psz_name = strdup(psz_entry);
339 (p_vcd->p_entries[i] - vcdinfo_get_track_lba(p_vcd->vcd, i_track))
342 dbg_print( INPUT_DBG_MRL,
343 "%s, lsn %d, byte_offset %ld",
344 s->psz_name, p_vcd->p_entries[i],
345 (unsigned long int) s->i_byte_offset);
346 TAB_APPEND( p_vcd->p_title[i_track-1]->i_seekpoint,
347 p_vcd->p_title[i_track-1]->seekpoint, s );
350 msg_Warn( p_access, "wrong track number found in entry points" );
352 p_vcd->b_valid_ep = VLC_TRUE;
357 /*****************************************************************************
358 * VCDSegments: Reads the information about the segments the disc.
359 *****************************************************************************/
361 VCDSegments( access_t * p_access )
363 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
367 p_vcd->i_segments = vcdinfo_get_num_segments(p_vcd->vcd);
369 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
370 "Segments: %d", p_vcd->i_segments);
372 if ( 0 == p_vcd->i_segments ) return VLC_FALSE;
374 t = p_vcd->p_title[p_vcd->i_titles] = vlc_input_title_New();
377 t->i_size = 0; /* Not sure Segments have a size associated */
378 t->psz_name = strdup(_("Segments"));
380 /* We have one additional segment allocated so we can get the size
381 by subtracting seg[i+1] - seg[i].
383 p_vcd->p_segments = malloc( sizeof( lsn_t ) * (p_vcd->i_segments+1) );
384 if( p_vcd->p_segments == NULL )
386 LOG_ERR ("not enough memory for segment treatment" );
390 for( i = 0 ; i < p_vcd->i_segments ; i++ )
392 char psz_segment[100];
393 seekpoint_t *s = vlc_seekpoint_New();
394 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
396 snprintf( psz_segment, sizeof(psz_segment), "%s%02d", _("Segment "),
399 s->i_byte_offset = 0; /* Not sure what this would mean here */
400 s->psz_name = strdup(psz_segment);
401 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
404 p_vcd->p_segments[p_vcd->i_segments] =
405 p_vcd->p_segments[p_vcd->i_segments-1]+
406 vcdinfo_get_seg_sector_count(p_vcd->vcd, p_vcd->i_segments-1);
411 /*****************************************************************************
412 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
414 We start area addressing for tracks at 1 since the default area 0
415 is reserved for segments.
416 *****************************************************************************/
418 VCDTitles( access_t * p_access )
420 /* We'll assume a VCD has its first MPEG track
421 cdio_get_first_track_num()+1 could be used if one wanted to be
422 very careful about this. Note: cdio_get_first_track() will give the
423 ISO-9660 track before the MPEG tracks.
426 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
429 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
433 for( i = 1 ; i <= p_vcd->i_tracks ; i++ )
435 input_title_t *t = p_vcd->p_title[i-1] = vlc_input_title_New();
437 uint32_t i_secsize = vcdinfo_get_track_sect_count( p_vcd->vcd, i );
439 snprintf( psz_track, sizeof(psz_track), "%s%02d", _("Track "),
442 t->i_size = (i_secsize) * (int64_t) M2F2_SECTOR_SIZE;
443 t->psz_name = strdup(psz_track);
445 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld",
455 /*****************************************************************************
456 VCDLIDs: Reads the LIST IDs from the LOT.
457 *****************************************************************************/
459 VCDLIDs( access_t * p_access )
461 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
463 unsigned int i_lid, i_title;
465 p_vcd->i_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
466 p_vcd->i_lid = VCDINFO_INVALID_ENTRY;
468 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
469 "LIDs: %d", p_vcd->i_lids);
471 if ( 0 == p_vcd->i_lids ) return VLC_FALSE;
473 if (vcdinfo_read_psd (p_vcd->vcd)) {
475 vcdinfo_visit_lot (p_vcd->vcd, VLC_FALSE);
479 We need to change libvcdinfo to be more robust when there are
480 problems reading the extended PSD. Given that area-highlighting and
481 selection features in the extended PSD haven't been implemented,
482 it's best then to not try to read this at all.
484 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
485 vcdinfo_visit_lot (p_vcd->vcd, VLC_TRUE);
489 /* Set up LIDs Navigation Menu */
490 t = vlc_input_title_New();
491 t->b_menu = VLC_TRUE;
492 t->psz_name = strdup( "LIDs" );
494 i_title = p_vcd->i_tracks;
495 for( i_lid = 1 ; i_lid <= p_vcd->i_lids ; i_lid++ )
498 seekpoint_t *s = vlc_seekpoint_New();
500 snprintf( psz_lid, sizeof(psz_lid), "%s%02d", _("LID "),
503 s->i_byte_offset = 0; /* A lid doesn't have an offset
504 size associated with it */
505 s->psz_name = strdup(psz_lid);
506 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
510 #if DYNAMICALLY_ALLOCATED
511 TAB_APPEND( p_vcd->i_titles, p_vcd->p_title, t );
513 p_vcd->p_title[p_vcd->i_titles] = t;
520 /*****************************************************************************
521 * VCDParse: parse command line
522 *****************************************************************************/
524 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
525 /*out*/ vlc_bool_t *play_single_item )
527 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
532 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
533 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
535 *play_single_item = VLC_FALSE;
539 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
544 /* On Win32 we want the VCD access plugin to be explicitly requested,
545 * we end up with lots of problems otherwise */
546 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
549 if( !p_access->psz_path )
554 psz_parser = psz_source = strdup( p_access->psz_path );
556 /* Parse input string :
557 * [device][@[type][title]] */
558 while( *psz_parser && *psz_parser != '@' )
563 if( *psz_parser == '@' )
565 /* Found the divide between the source name and the
566 type+entry number. */
573 switch(*psz_parser) {
575 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
577 *play_single_item = VLC_TRUE;
580 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
582 *play_single_item = VLC_FALSE;
585 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
587 *play_single_item = VLC_TRUE;
590 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
592 *play_single_item = VLC_TRUE;
598 num = strtol( psz_parser, &psz_next, 10 );
599 if ( *psz_parser != '\0' && *psz_next == '\0')
605 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
611 /* No source specified, so figure it out. */
612 if( !p_access->psz_access ) return NULL;
614 psz_source = config_GetPsz( p_access, "vcd" );
616 if( !psz_source || 0==strlen(psz_source) ) {
617 /* Scan for a CD-ROM drive with a VCD in it. */
618 char **cd_drives = cdio_get_devices_with_cap( NULL,
619 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
620 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
622 if( NULL == cd_drives ) return NULL;
623 if( cd_drives[0] == NULL )
625 cdio_free_device_list( cd_drives );
628 psz_source = strdup( cd_drives[0] );
629 cdio_free_device_list( cd_drives );
633 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
634 "source=%s entry=%d type=%d",
635 psz_source, p_itemid->num, p_itemid->type);
641 Set's start origin subsequent seeks/reads
644 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
645 const vcdinfo_itemid_t *p_itemid )
647 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
649 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
650 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
653 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
655 p_access->info.i_pos = ( i_lsn - p_vcd->track_lsn )
657 p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
658 | INPUT_UPDATE_SEEKPOINT;
661 switch (p_vcd->play_item.type) {
662 case VCDINFO_ITEM_TYPE_ENTRY:
663 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
664 "chapter", _("Entry"), "Setting entry/segment");
665 p_access->info.i_title = i_track-1;
666 p_access->info.i_size = p_vcd->p_title[i_track-1]->i_size;
667 p_access->info.i_seekpoint = p_itemid->num;
670 case VCDINFO_ITEM_TYPE_SEGMENT:
671 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
672 "chapter", _("Segment"), "Setting entry/segment");
673 /* The last title entry is the for segments (when segments exist
674 and they must here. The segment seekpoints are stored after
675 the entry seekpoints and (zeroed) lid seekpoints.
677 p_access->info.i_title = p_vcd->i_titles - 1;
678 p_access->info.i_size = 150 * M2F2_SECTOR_SIZE;
679 p_access->info.i_seekpoint = p_vcd->i_entries
680 + p_vcd->i_lids + p_itemid->num;
683 case VCDINFO_ITEM_TYPE_TRACK:
684 p_access->info.i_title = i_track-1;
685 p_access->info.i_size = p_vcd->p_title[i_track-1]->i_size;
686 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcd->vcd,
690 msg_Warn( p_access, "can't set origin for play type %d",
691 p_vcd->play_item.type );
695 VCDUpdateTitle( p_access );
699 /*****************************************************************************
700 * vcd_Open: Opens a VCD device or file initializes, a list of
701 tracks, segements and entry lsns and sizes and returns an opaque handle.
702 *****************************************************************************/
703 static vcdinfo_obj_t *
704 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
706 access_t *p_access = (access_t *)p_this;
707 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
708 vcdinfo_obj_t *p_vcdobj;
712 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
714 if( !psz_dev ) return NULL;
716 actual_dev=strdup(psz_dev);
717 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
725 Save summary info on tracks, segments and entries...
728 if ( 0 < (p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
729 p_vcd->track = (vcdplayer_play_item_info_t *)
730 calloc(p_vcd->i_tracks, sizeof(vcdplayer_play_item_info_t));
732 for (i=0; i<p_vcd->i_tracks; i++) {
733 unsigned int track_num=i+1;
734 p_vcd->track[i].size =
735 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
736 p_vcd->track[i].start_LSN =
737 vcdinfo_get_track_lsn(p_vcdobj, track_num);
742 if ( 0 < (p_vcd->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
743 p_vcd->entry = (vcdplayer_play_item_info_t *)
744 calloc(p_vcd->i_entries, sizeof(vcdplayer_play_item_info_t));
746 for (i=0; i<p_vcd->i_entries; i++) {
747 p_vcd->entry[i].size = vcdinfo_get_entry_sect_count(p_vcdobj, i);
748 p_vcd->entry[i].start_LSN = vcdinfo_get_entry_lba(p_vcdobj, i);
753 if ( 0 < (p_vcd->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
754 p_vcd->segment = (vcdplayer_play_item_info_t *)
755 calloc(p_vcd->i_segments, sizeof(vcdplayer_play_item_info_t));
757 for (i=0; i<p_vcd->i_segments; i++) {
758 p_vcd->segment[i].size = vcdinfo_get_seg_sector_count(p_vcdobj, i);
759 p_vcd->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
762 p_vcd->segment = NULL;
768 /****************************************************************************
769 Update the "varname" variable to i_num without triggering a callback.
770 ****************************************************************************/
772 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
773 const char *p_varname, char *p_label,
774 const char *p_debug_label)
779 const vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
780 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
784 text.psz_string = p_label;
785 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
787 var_Change( p_access, p_varname, i_action, &val, NULL );
791 /*****************************************************************************
793 *****************************************************************************/
795 /*****************************************************************************
797 read in meta-information about VCD: the number of tracks, segments,
798 entries, size and starting information. Then set up state variables so
799 that we read/seek starting at the location specified.
801 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
802 and VLC_EGENERIC for some other error.
803 *****************************************************************************/
805 E_(VCDOpen) ( vlc_object_t *p_this )
807 access_t *p_access = (access_t *)p_this;
810 vcdinfo_itemid_t itemid;
811 vlc_bool_t play_single_item = VLC_FALSE;
813 p_access->pf_read = NULL;
814 p_access->pf_block = VCDReadBlock;
815 p_access->pf_control = VCDControl;
816 p_access->pf_seek = VCDSeek;
818 p_access->info.i_update = 0;
819 p_access->info.i_size = 0;
820 p_access->info.i_pos = 0;
821 p_access->info.b_eof = VLC_FALSE;
822 p_access->info.i_title = 0;
823 p_access->info.i_seekpoint = 0;
825 p_vcd = malloc( sizeof(vcdplayer_t) );
829 LOG_ERR ("out of memory" );
833 p_access->p_sys = (access_sys_t *) p_vcd;
835 /* Set where to log errors messages from libcdio. */
836 p_vcd_access = p_access;
837 cdio_log_set_handler ( cdio_log_handler );
838 vcd_log_set_handler ( vcd_log_handler );
840 psz_source = VCDParse( p_access, &itemid, &play_single_item );
842 if ( NULL == psz_source )
845 return( VLC_EGENERIC );
848 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
849 psz_source, p_access->psz_path );
851 p_vcd->psz_source = strdup(psz_source);
852 p_vcd->i_debug = config_GetInt( p_this,
853 MODULE_STRING "-debug" );
854 p_vcd->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
855 "-blocks-per-read" );
856 p_vcd->in_still = VLC_FALSE;
857 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
858 p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT,
860 p_vcd->p_meta = vlc_meta_New();
861 p_vcd->p_segments = NULL;
862 p_vcd->p_entries = NULL;
866 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
868 msg_Warn( p_access, "could not open %s", psz_source );
872 p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
874 /* Get track information. */
875 p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcd->vcd);
877 if( p_vcd->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcd->i_tracks ) {
878 vcdinfo_close( p_vcd->vcd );
879 LOG_ERR ("no movie tracks found" );
883 /* Build Navigation Title table for the tracks. */
884 VCDTitles( p_access );
886 /* Add into the above entry points as "Chapters". */
887 if( ! VCDEntryPoints( p_access ) )
889 msg_Warn( p_access, "could not read entry points, will not use them" );
890 p_vcd->b_valid_ep = VLC_FALSE;
893 /* Initialize LID info and add that as a menu item */
894 if( ! VCDLIDs( p_access ) )
896 msg_Warn( p_access, "could not read entry LIDs" );
899 /* Do we set PBC (via LID) on? */
901 ( VCDINFO_ITEM_TYPE_LID == itemid.type && p_vcd->i_lids > itemid.num )
903 : VCDINFO_INVALID_ENTRY;
905 /* Initialize segment information and add that a "Track". */
906 VCDSegments( p_access );
908 vcdplayer_play( p_access, itemid );
910 p_access->psz_demux = strdup( "ps" );
913 p_vcd->p_intf = intf_Create( p_access, "vcdx" );
914 p_vcd->p_intf->b_block = VLC_FALSE;
915 intf_RunThread( p_vcd->p_intf );
919 if (play_single_item)
920 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
934 /*****************************************************************************
935 * VCDClose: closes VCD releasing allocated memory.
936 *****************************************************************************/
938 E_(VCDClose) ( vlc_object_t *p_this )
940 access_t *p_access = (access_t *)p_this;
941 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
943 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
945 vcdinfo_close( p_vcd->vcd );
947 FREE_AND_NULL( p_vcd->p_entries );
948 FREE_AND_NULL( p_vcd->p_segments );
949 FREE_AND_NULL( p_vcd->psz_source );
950 FREE_AND_NULL( p_vcd->track );
951 FREE_AND_NULL( p_vcd->segment );
952 FREE_AND_NULL( p_vcd->entry );
955 p_access->p_sys = NULL;
959 /*****************************************************************************
960 * Control: The front-end or vlc engine calls here to ether get
961 * information such as meta information or plugin capabilities or to
962 * issue miscellaneous "set" requests.
963 *****************************************************************************/
964 static int VCDControl( access_t *p_access, int i_query, va_list args )
966 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
970 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
971 "query %d", i_query );
975 /* Pass back a copy of meta information that was gathered when we
976 during the Open/Initialize call.
978 case ACCESS_GET_META:
980 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
982 dbg_print( INPUT_DBG_EVENT, "get meta info" );
984 if ( p_vcd->p_meta ) {
985 *pp_meta = vlc_meta_Duplicate( p_vcd->p_meta );
986 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
988 msg_Warn( p_access, "tried to copy NULL meta info" );
994 case ACCESS_CAN_SEEK:
995 case ACCESS_CAN_FASTSEEK:
996 case ACCESS_CAN_PAUSE:
997 case ACCESS_CAN_CONTROL_PACE:
999 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1001 dbg_print( INPUT_DBG_EVENT,
1002 "seek/fastseek/pause/can_control_pace" );
1003 *pb_bool = VLC_TRUE;
1009 case ACCESS_GET_MTU:
1010 pi_int = (int*)va_arg( args, int * );
1011 *pi_int = (p_vcd->i_blocks_per_read * M2F2_SECTOR_SIZE);
1012 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1015 case ACCESS_GET_PTS_DELAY:
1017 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1018 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1019 * MILLISECONDS_PER_SEC;
1020 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1026 case ACCESS_SET_PAUSE_STATE:
1027 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1031 case ACCESS_GET_TITLE_INFO:
1033 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1034 + strlen(p_vcd->psz_source) + sizeof("@E999")+3;
1035 input_title_t ***ppp_title
1036 = (input_title_t***)va_arg( args, input_title_t*** );
1037 char *psz_mrl = malloc( psz_mrl_max );
1040 pi_int = (int*)va_arg( args, int* );
1042 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1045 if( psz_mrl == NULL ) {
1046 msg_Warn( p_access, "out of memory" );
1048 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1049 VCD_MRL_PREFIX, p_vcd->psz_source);
1050 VCDMetaInfo( p_access, psz_mrl );
1054 /* Duplicate title info */
1055 if( p_vcd->i_titles == 0 )
1057 *pi_int = 0; ppp_title = NULL;
1060 *pi_int = p_vcd->i_titles;
1061 *ppp_title = malloc(sizeof( input_title_t **) * p_vcd->i_titles );
1063 if (!*ppp_title) return VLC_ENOMEM;
1065 for( i = 0; i < p_vcd->i_titles; i++ )
1067 if ( p_vcd->p_title[i] )
1069 vlc_input_title_Duplicate( p_vcd->p_title[i] );
1074 case ACCESS_SET_TITLE:
1075 i = (int)va_arg( args, int );
1077 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1078 if( i != p_access->info.i_title )
1080 vcdinfo_itemid_t itemid;
1081 track_t i_track = i+1;
1082 unsigned int i_entry =
1083 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
1085 /* FIXME! For now we are assuming titles are only
1086 tracks and that track == title+1 */
1087 itemid.num = i_track;
1088 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1090 VCDSetOrigin(p_access,
1091 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
1096 case ACCESS_SET_SEEKPOINT:
1098 input_title_t *t = p_vcd->p_title[p_access->info.i_title];
1099 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1101 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1102 if( t->i_seekpoint > 0 )
1104 track_t i_track = p_access->info.i_title+1;
1107 /* FIXME! For now we are assuming titles are only
1108 tracks and that track == title+1 and we the play
1109 item is entries (not tracks or lids).
1110 We need to generalize all of this.
1113 if (i < p_vcd->i_entries)
1115 p_vcd->play_item.num = i;
1116 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1117 lsn = vcdinfo_get_entry_lba(p_vcd->vcd, i);
1118 } else if ( i < p_vcd->i_entries + p_vcd->i_lids )
1120 p_vcd->play_item.num = i = i - p_vcd->i_entries;
1121 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_LID;
1125 p_vcd->play_item.num = i = i - p_vcd->i_entries
1127 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1128 lsn = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
1131 VCDSetOrigin( p_access,
1132 vcdinfo_get_entry_lba(p_vcd->vcd, i),
1133 i_track, &(p_vcd->play_item) );
1138 case ACCESS_SET_PRIVATE_ID_STATE:
1139 dbg_print( INPUT_DBG_EVENT, "set private id" );
1140 return VLC_EGENERIC;
1143 msg_Warn( p_access, "unimplemented query in control" );
1144 return VLC_EGENERIC;