1 /*****************************************************************************
2 * vcd.c : VCD input module for vlc
3 * using libcdio, libvcd and libvcdinfo. vlc-specific things tend
5 *****************************************************************************
6 * Copyright (C) 2000, 2003, 2004 VideoLAN
9 * Authors: Rocky Bernstein <rocky@panix.com>
10 * Some code is based on the non-libcdio VCD plugin (as there really
11 * isn't real documentation yet.)
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
34 #include <vlc/input.h>
37 #include "vcdplayer.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>
51 /* how many blocks VCDRead will read in each loop */
52 #define VCD_BLOCKS_ONCE 20
54 /*****************************************************************************
56 *****************************************************************************/
58 /* First those which are accessed from outside (via pointers). */
59 static block_t *VCDReadBlock ( access_t * );
61 static int VCDControl ( access_t *p_access, int i_query,
64 /* Now those which are strictly internal */
65 static void VCDSetOrigin ( access_t *p_access,
67 lsn_t i_lsn, lsn_t end_lsn,
69 const vcdinfo_itemid_t * p_itemid );
70 static int VCDEntryPoints ( access_t * );
71 static int VCDLIDs ( access_t * );
73 static int VCDSegments ( access_t * );
75 static int VCDTitles ( access_t * );
76 static int VCDReadSector ( vlc_object_t *p_this,
77 const vcdinfo_obj_t *p_vcd, lsn_t i_lsn,
79 static char *VCDParse ( access_t *,
80 /*out*/ vcdinfo_itemid_t * p_itemid ,
81 /*out*/ vlc_bool_t *play_single_item );
83 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
84 const char *p_varname, char *p_label,
85 const char *p_debug_label );
87 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
89 /****************************************************************************
91 ****************************************************************************/
93 /* FIXME: This variable is a hack. Would be nice to eliminate the
96 static access_t *p_vcd_access = NULL;
98 /* process messages that originate from libcdio. */
100 cdio_log_handler (cdio_log_level_t level, const char message[])
102 const access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
106 if (p_vcd->i_debug & INPUT_DBG_CDIO)
107 msg_Dbg( p_vcd_access, message);
110 msg_Warn( p_vcd_access, message);
113 case CDIO_LOG_ASSERT:
114 msg_Err( p_vcd_access, message);
117 msg_Warn( p_vcd_access, message,
118 _("The above message had unknown log level"),
124 /* process messages that originate from vcdinfo. */
126 vcd_log_handler (vcd_log_level_t level, const char message[])
128 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
132 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
133 msg_Dbg( p_vcd_access, message);
136 msg_Warn( p_vcd_access, message);
140 msg_Err( p_vcd_access, message);
143 msg_Warn( p_vcd_access, "%s\n%s %d", message,
144 _("The above message had unknown vcdimager log level"),
150 /*****************************************************************************
151 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
152 NULL is returned if something went wrong.
153 *****************************************************************************/
155 VCDReadBlock( access_t * p_access )
157 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
159 int i_blocks = VCD_BLOCKS_ONCE;
162 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
166 dbg_print( (INPUT_DBG_CALL), "lsn: %lu",
167 (long unsigned int) p_vcd->i_lsn );
169 /* Compute the number of blocks we have to read */
171 i_blocks = VCD_BLOCKS_ONCE ;
173 /* Allocate a block for the reading */
174 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
176 msg_Err( p_access, "cannot get a new block of size: %i",
177 i_blocks * M2F2_SECTOR_SIZE );
178 block_Release( p_block );
182 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
185 if ( p_vcd->i_lsn == p_vcd->end_lsn ) {
186 vcdplayer_read_status_t read_status;
188 /* We've run off of the end of this entry. Do we continue or stop? */
189 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
190 "end reached, cur: %lu",
191 (long unsigned int) p_vcd->i_lsn );
193 read_status = vcdplayer_pbc_is_on( p_vcd )
194 ? vcdplayer_pbc_nav( p_access )
195 : vcdplayer_non_pbc_nav( p_access );
197 switch (read_status) {
199 /* End reached. Return NULL to indicated this. */
201 /* Some sort of error. */
204 case READ_STILL_FRAME:
206 /* Reached the end of a still frame. */
207 byte_t * p_buf = (byte_t *) p_block->p_buffer;
209 p_buf += (i_index*M2F2_SECTOR_SIZE);
210 memset(p_buf, 0, M2F2_SECTOR_SIZE);
213 dbg_print(INPUT_DBG_STILL, "Handled still event");
215 p_vcd->p_intf->p_sys->b_still = VLC_TRUE;
216 var_SetInteger( p_access, "state", PAUSE_S );
226 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
228 (byte_t *) p_block->p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
230 LOG_ERR ("could not read sector %lu",
231 (long unsigned int) p_vcd->i_lsn );
239 if ( i_index != i_blocks ) /* this should not happen */
241 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
242 p_vcd->i_lsn, p_last_sector ) < 0 )
244 LOG_ERR ("could not read sector %lu",
245 (long unsigned int) p_vcd->i_lsn );
251 /* Update seekpoints */
252 for( i_read = 0; i_read < i_blocks; i_read++ )
254 input_title_t *t = p_vcd->p_title[p_access->info.i_title];
256 if( t->i_seekpoint > 0 &&
257 p_access->info.i_seekpoint + 1 < t->i_seekpoint &&
258 p_access->info.i_pos + i_read * M2F2_SECTOR_SIZE >=
259 t->seekpoint[p_access->info.i_seekpoint+1]->i_byte_offset )
261 msg_Dbg( p_access, "seekpoint change" );
262 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
263 p_access->info.i_seekpoint++;
267 /* Update a few values */
268 p_vcd->i_lsn += i_blocks;
269 p_access->info.i_pos += p_block->i_buffer;
275 /****************************************************************************
277 ****************************************************************************/
279 VCDSeek( access_t * p_access, int64_t i_pos )
281 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
284 access_vcd_data_t *p_vcd =
285 (access_vcd_data_t *)p_vcd_access->p_sys;
286 const input_title_t *t = p_vcd->p_title[p_access->info.i_title];
288 unsigned int i_entry=VCDINFO_INVALID_ENTRY;
290 /* Next sector to read */
291 p_access->info.i_pos = i_pos;
292 p_vcd->i_lsn = (i_pos / (int64_t)M2F2_SECTOR_SIZE) +
296 if( p_vcd->b_valid_ep )
298 for( i_entry = 0 ; i_entry < p_vcd->i_entries ; i_entry ++ )
300 if( p_vcd->i_lsn < p_vcd->p_entries[i_entry] )
302 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
303 "chapter", _("Entry"), "Setting entry" );
307 p_vcd->play_item.num = i_entry;
308 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
312 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
314 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
315 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
318 /* Update current seekpoint */
319 if( i_seekpoint != p_access->info.i_seekpoint )
321 msg_Dbg( p_access, "seekpoint change" );
322 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
323 p_access->info.i_seekpoint = i_seekpoint;
326 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
327 "orig %lu, cur: %lu, offset: %lld, entry %d",
328 (long unsigned int) p_vcd->origin_lsn,
329 (long unsigned int) p_vcd->i_lsn, i_pos,
337 /*****************************************************************************
338 VCDPlay: set up internal structures so seeking/reading places an item.
339 itemid: the thing to play.
340 user_entry: true if itemid is a user selection (rather than internally-
341 generated selection such as via PBC) in which case we may have to adjust
342 for differences in numbering.
343 *****************************************************************************/
345 VCDPlay( access_t *p_access, vcdinfo_itemid_t itemid )
347 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
351 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
353 const vlc_bool_t b_was_still = p_vcd->in_still;
356 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
357 itemid.num, itemid.type);
359 switch (itemid.type) {
360 case VCDINFO_ITEM_TYPE_TRACK:
363 track_t i_track = itemid.num;
364 unsigned int i_entry =
365 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
367 /* Valid tracks go from 1...i_tracks-1, because track 0 is
370 if (i_track == 0 || i_track >= p_vcd->i_tracks) {
371 LOG_ERR ("Invalid track number %d", i_track );
374 p_vcd->in_still = VLC_FALSE;
375 VCDSetOrigin( p_access, p_vcd->p_sectors[i_track],
376 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
377 p_vcd->p_sectors[i_track+1],
382 case VCDINFO_ITEM_TYPE_SEGMENT:
384 int i_seg = itemid.num;
386 /* Valid segments go from 0...i_segments-1. */
387 if (itemid.num >= p_vcd->i_segments) {
388 LOG_ERR ( "Invalid segment number: %d", i_seg );
391 vcdinfo_video_segment_type_t segtype =
392 vcdinfo_get_video_type(p_vcd->vcd, i_seg);
394 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
395 vcdinfo_video_type2str(p_vcd->vcd, i_seg),
396 (int) segtype, itemid.num);
400 case VCDINFO_FILES_VIDEO_NTSC_STILL:
401 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
402 case VCDINFO_FILES_VIDEO_PAL_STILL:
403 case VCDINFO_FILES_VIDEO_PAL_STILL2:
404 p_vcd->in_still = VLC_TRUE;
407 p_vcd->in_still = VLC_FALSE;
409 VCDSetOrigin( p_access, p_vcd->p_segments[i_seg],
410 p_vcd->p_segments[i_seg],
411 p_vcd->p_segments[i_seg+1],
418 case VCDINFO_ITEM_TYPE_LID:
419 /* LIDs go from 1..i_lids. */
420 if (itemid.num == 0 || itemid.num > p_vcd->i_lids) {
421 LOG_ERR ( "Invalid LID number: %d", itemid.num );
424 p_vcd->i_lid = itemid.num;
425 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
427 switch (p_vcd->pxd.descriptor_type) {
429 case PSD_TYPE_SELECTION_LIST:
430 case PSD_TYPE_EXT_SELECTION_LIST: {
431 vcdinfo_itemid_t trans_itemid;
432 uint16_t trans_itemid_num;
434 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
435 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
436 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
437 p_vcd->loop_count = 1;
438 p_vcd->loop_item = trans_itemid;
439 return VCDPlay( p_access, trans_itemid );
443 case PSD_TYPE_PLAY_LIST: {
444 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
446 return vcdplayer_inc_play_item(p_access)
447 ? VLC_SUCCESS : VLC_EGENERIC;
451 case PSD_TYPE_END_LIST:
452 case PSD_TYPE_COMMAND_LIST:
459 case VCDINFO_ITEM_TYPE_ENTRY:
461 int i_entry = itemid.num;
463 /* Entries go from 0..i_entries-1. */
464 if (itemid.num >= p_vcd->i_entries) {
465 LOG_ERR ("Invalid entry number: %d", i_entry );
468 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i_entry);
469 p_vcd->in_still = VLC_FALSE;
470 VCDSetOrigin( p_access, p_vcd->p_sectors[i_track],
471 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
472 p_vcd->p_sectors[i_track+1],
479 LOG_ERR ("unknown entry type" );
483 p_vcd->play_item = itemid;
491 /*****************************************************************************
492 VCDEntryPoints: Reads the information about the entry points on the disc
493 and initializes area information with that.
494 Before calling this track information should have been read in.
495 *****************************************************************************/
497 VCDEntryPoints( access_t * p_access )
499 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
502 access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
503 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcd->vcd);
504 const track_t i_last_track
505 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcd->vcd))
506 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcd->vcd));
509 if (0 == i_entries) {
510 LOG_ERR ("no entires found -- something is wrong" );
514 p_vcd->p_entries = malloc( sizeof( lsn_t ) * i_entries );
516 if( p_vcd->p_entries == NULL )
518 LOG_ERR ("not enough memory for entry points treatment" );
522 p_vcd->i_entries = i_entries;
524 for( i = 0 ; i < i_entries ; i++ )
526 const track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
527 if( i_track <= i_last_track ) {
528 seekpoint_t *s = vlc_seekpoint_New();
531 snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
533 p_vcd->p_entries[i] = vcdinfo_get_entry_lsn(p_vcd->vcd, i);
535 s->psz_name = strdup(psz_entry);
536 s->i_byte_offset = (p_vcd->p_entries[i] - p_vcd->p_sectors[i_track])
539 TAB_APPEND( p_vcd->p_title[i_track-1]->i_seekpoint,
540 p_vcd->p_title[i_track-1]->seekpoint, s );
542 msg_Warn( p_access, "wrong track number found in entry points" );
544 p_vcd->b_valid_ep = VLC_TRUE;
551 /*****************************************************************************
552 * VCDSegments: Reads the information about the segments the disc.
553 *****************************************************************************/
555 VCDSegments( access_t * p_access )
557 access_vcd_data_t * p_vcd;
559 unsigned int i_segments;
562 p_vcd = (access_vcd_data_t *) p_access->p_sys;
563 i_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
565 #define area p_access->stream.pp_areas
567 /* area 0 is reserved for segments. Set Absolute start offset
569 area[0]->i_plugin_data = 0;
570 input_DelArea( p_access, area[0] );
571 input_AddArea( p_access, 0, 0 );
573 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
574 * (off_t)M2F2_SECTOR_SIZE;
575 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
576 * (off_t)M2F2_SECTOR_SIZE;
578 /* Default Segment */
581 /* i_plugin_data is used to store which entry point is the first
582 of the track (area) */
583 area[0]->i_plugin_data = 0;
585 area[0]->i_part_nb = 0;
587 dbg_print( INPUT_DBG_MRL,
588 "area[0] id: %d, i_start: %lld, i_size: %lld",
589 area[0]->i_id, area[0]->i_start, area[0]->i_size );
591 if (i_segments == 0) return 0;
593 /* We have one additional segment allocated so we can get the size
594 by subtracting seg[i+1] - seg[i].
596 p_vcd->p_segments = malloc( sizeof( lsn_t ) * (i_segments+1) );
597 if( p_vcd->p_segments == NULL )
599 LOG_ERR ("not enough memory for segment treatment" );
603 /* Update the navigation variables without triggering a callback */
604 VCDUpdateVar( p_access, 0, VLC_VAR_SETVALUE, "title", _("Track"),
607 var_Change( p_access, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
609 for( i = 0 ; i < i_segments ; i++ )
611 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
612 area[0]->i_part_nb ++;
613 VCDUpdateVar( p_access, i , VLC_VAR_ADDCHOICE,
614 "chapter", _("Segment"), "Adding segment choice");
619 p_vcd->p_segments[i_segments] = p_vcd->p_segments[i_segments-1]+
620 vcdinfo_get_seg_sector_count(p_vcd->vcd, i_segments-1);
626 /*****************************************************************************
627 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
629 We start area addressing for tracks at 1 since the default area 0
630 is reserved for segments.
631 *****************************************************************************/
633 VCDTitles( access_t * p_access )
635 /* We'll assume a VCD has its first MPEG track
636 cdio_get_first_track_num()+1 could be used if one wanted to be
637 very careful about this. Note: cdio_get_first_track() will give the
638 ISO-9660 track before the MPEG tracks.
640 const unsigned int i_first_mpeg_track=2;
642 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
645 access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
649 for( i = 2 ; i <= p_vcd->i_tracks ; i++ )
651 input_title_t *t = p_vcd->p_title[i - i_first_mpeg_track]
652 = vlc_input_title_New();
655 cdio_get_track_sec_count( vcdinfo_get_cd_image(p_vcd->vcd), i );
657 snprintf(psz_track, sizeof(psz_track), "%s%02d", _("Track "),
660 t->i_size = (i_secsize) * (int64_t) M2F2_SECTOR_SIZE;
661 t->psz_name = strdup(psz_track);
663 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld",
673 /*****************************************************************************
674 VCDLIDs: Reads the LIST IDs from the LOT.
675 *****************************************************************************/
677 VCDLIDs( access_t * p_access )
679 access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
681 p_vcd->i_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
682 p_vcd->i_lid = VCDINFO_INVALID_ENTRY;
684 if (vcdinfo_read_psd (p_vcd->vcd)) {
686 vcdinfo_visit_lot (p_vcd->vcd, VLC_FALSE);
690 We need to change libvcdinfo to be more robust when there are
691 problems reading the extended PSD. Given that area-highlighting and
692 selection features in the extended PSD haven't been implemented,
693 it's best then to not try to read this at all.
695 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
696 vcdinfo_visit_lot (p_vcd->vcd, VLC_TRUE);
700 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
701 "num LIDs=%d", p_vcd->i_lids);
706 /*****************************************************************************
707 * VCDParse: parse command line
708 *****************************************************************************/
710 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
711 /*out*/ vlc_bool_t *play_single_item )
713 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_access->p_sys;
718 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
719 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
721 *play_single_item = VLC_FALSE;
725 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
730 /* On Win32 we want the VCD access plugin to be explicitly requested,
731 * we end up with lots of problems otherwise */
732 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
735 if( !p_access->psz_path )
740 psz_parser = psz_source = strdup( p_access->psz_path );
742 /* Parse input string :
743 * [device][@[type][title]] */
744 while( *psz_parser && *psz_parser != '@' )
749 if( *psz_parser == '@' )
751 /* Found the divide between the source name and the
752 type+entry number. */
759 switch(*psz_parser) {
761 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
763 *play_single_item = VLC_TRUE;
766 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
768 *play_single_item = VLC_FALSE;
771 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
773 *play_single_item = VLC_TRUE;
776 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
778 *play_single_item = VLC_TRUE;
784 num = strtol( psz_parser, &psz_next, 10 );
785 if ( *psz_parser != '\0' && *psz_next == '\0')
791 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
797 /* No source specified, so figure it out. */
798 if( !p_access->psz_access ) return NULL;
800 psz_source = config_GetPsz( p_access, "vcd" );
802 if( !psz_source || 0==strlen(psz_source) ) {
803 /* Scan for a CD-ROM drive with a VCD in it. */
804 char **cd_drives = cdio_get_devices_with_cap( NULL,
805 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
806 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
808 if( NULL == cd_drives ) return NULL;
809 if( cd_drives[0] == NULL )
811 cdio_free_device_list( cd_drives );
814 psz_source = strdup( cd_drives[0] );
815 cdio_free_device_list( cd_drives );
819 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
820 "source=%s entry=%d type=%d",
821 psz_source, p_itemid->num, p_itemid->type);
827 Set's start origin subsequent seeks/reads
830 VCDSetOrigin( access_t *p_access, lsn_t origin_lsn,
831 lsn_t i_lsn, lsn_t end_lsn, track_t i_track,
832 const vcdinfo_itemid_t *p_itemid )
834 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
836 p_vcd->origin_lsn = origin_lsn;
837 p_vcd->i_lsn = i_lsn;
838 p_vcd->end_lsn = end_lsn;
839 p_vcd->i_track = i_track;
840 p_vcd->play_item.num = p_itemid->num;
841 p_vcd->play_item.type = p_itemid->type;
843 p_access->info.i_title = i_track-1;
844 p_access->info.i_seekpoint = p_itemid->num;
845 p_access->info.i_size = p_vcd->p_title[i_track]->i_size;
846 p_access->info.i_pos = ( i_lsn - origin_lsn ) * M2F2_SECTOR_SIZE;
848 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
849 "origin: %lu, cur_lsn: %lu, end_lsn: %lu, track: %d",
850 (long unsigned int) origin_lsn,
851 (long unsigned int) i_lsn,
852 (long unsigned int) end_lsn, i_track );
854 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
856 p_itemid->type == VCDINFO_ITEM_TYPE_ENTRY ?
857 _("Entry") : _("Segment"),
858 "Setting entry/segment");
861 /*****************************************************************************
862 * vcd_Open: Opens a VCD device or file and returns an opaque handle
863 *****************************************************************************/
864 static vcdinfo_obj_t *
865 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
867 vcdinfo_obj_t *p_vcdobj;
870 if( !psz_dev ) return NULL;
872 actual_dev=strdup(psz_dev);
873 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
883 /****************************************************************************
884 * VCDReadSector: Read a sector (2324 bytes)
885 ****************************************************************************/
887 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
888 lsn_t i_lsn, byte_t * p_buffer )
891 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
892 uint8_t data [M2F2_SECTOR_SIZE];
895 vcdsector_t vcd_sector;
897 if( cdio_read_mode2_sector( vcdinfo_get_cd_image( p_vcd ),
898 &vcd_sector, i_lsn, VLC_TRUE )
901 msg_Warn( p_this, "Could not read LSN %lu",
902 (long unsigned int) i_lsn );
906 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
911 /****************************************************************************
912 Update the "varname" variable to i_num without triggering a callback.
913 ****************************************************************************/
915 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
916 const char *p_varname, char *p_label,
917 const char *p_debug_label)
922 const access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
923 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
927 text.psz_string = p_label;
928 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
930 var_Change( p_access, p_varname, i_action, &val, NULL );
934 /*****************************************************************************
936 *****************************************************************************/
938 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
939 vlc_value_t oldval, vlc_value_t val, void *p_data )
941 access_vcd_data_t *p_vcd;
943 if (NULL == p_vcd_access) return VLC_EGENERIC;
945 p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
947 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
948 msg_Dbg( p_vcd_access, "Old debug (x%0x) %d, new debug (x%0x) %d",
949 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
951 p_vcd->i_debug = val.i_int;
956 /*****************************************************************************
958 read in meta-information about VCD: the number of tracks, segments,
959 entries, size and starting information. Then set up state variables so
960 that we read/seek starting at the location specified.
962 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
963 and VLC_EGENERIC for some other error.
964 *****************************************************************************/
966 E_(VCDOpen) ( vlc_object_t *p_this )
968 access_t * p_access = (access_t *)p_this;
969 access_vcd_data_t * p_vcd;
971 vcdinfo_itemid_t itemid;
972 vlc_bool_t b_play_ok;
973 vlc_bool_t play_single_item = VLC_FALSE;
975 p_access->pf_read = NULL;
976 p_access->pf_block = VCDReadBlock;
977 p_access->pf_control = VCDControl;
978 p_access->pf_seek = VCDSeek;
980 p_access->info.i_update = 0;
981 p_access->info.i_size = 0;
982 p_access->info.i_pos = 0;
983 p_access->info.b_eof = VLC_FALSE;
984 p_access->info.i_title = 0;
985 p_access->info.i_seekpoint = 0;
987 p_vcd = malloc( sizeof(access_vcd_data_t) );
991 LOG_ERR ("out of memory" );
995 p_access->p_sys = (access_sys_t *) p_vcd;
997 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
998 p_vcd->in_still = VLC_FALSE;
999 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
1000 p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT,
1002 p_vcd->p_meta = vlc_meta_New();
1004 /* Set where to log errors messages from libcdio. */
1005 p_vcd_access = p_access;
1006 cdio_log_set_handler ( cdio_log_handler );
1007 vcd_log_set_handler ( vcd_log_handler );
1009 psz_source = VCDParse( p_access, &itemid, &play_single_item );
1011 if ( NULL == psz_source )
1014 return( VLC_EGENERIC );
1017 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1018 psz_source, p_access->psz_path );
1020 p_vcd->p_segments = NULL;
1021 p_vcd->p_entries = NULL;
1025 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1027 msg_Warn( p_access, "could not open %s", psz_source );
1031 p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
1033 /* Get track information. */
1034 p_vcd->i_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_access),
1035 vcdinfo_get_cd_image(p_vcd->vcd),
1036 &p_vcd->p_sectors );
1037 if( p_vcd->i_tracks <= 1 ) {
1038 vcdinfo_close( p_vcd->vcd );
1039 LOG_ERR ("no movie tracks found" );
1044 /* Initialize segment information. */
1045 VCDSegments( p_access );
1048 /* Build Navigation Title table. */
1049 VCDTitles( p_access );
1051 /* Map entry points into Chapters */
1052 if( VCDEntryPoints( p_access ) < 0 )
1054 msg_Warn( p_access, "could not read entry points, will not use them" );
1055 p_vcd->b_valid_ep = VLC_FALSE;
1058 if( VCDLIDs( p_access ) < 0 )
1060 msg_Warn( p_access, "could not read entry LIDs" );
1064 b_play_ok = (VLC_SUCCESS == VCDPlay( p_access, itemid ));
1066 if ( ! b_play_ok ) {
1067 vcdinfo_close( p_vcd->vcd );
1071 /* We assume playing CD track 2 (1st MPEG data) for now */
1073 p_vcd->origin_lsn = p_vcd->i_lsn = p_vcd->p_sectors[1];
1074 p_access->info.i_title = 0;
1075 p_access->info.i_seekpoint = 0;
1076 p_access->info.i_size = p_vcd->p_title[0]->i_size;
1077 p_access->info.i_pos = 0;
1081 p_access->psz_demux = strdup( "ps" );
1084 p_vcd->p_intf = intf_Create( p_access, "vcdx" );
1085 p_vcd->p_intf->b_block = VLC_FALSE;
1086 intf_RunThread( p_vcd->p_intf );
1090 if (play_single_item)
1091 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
1102 return VLC_EGENERIC;
1105 /*****************************************************************************
1106 * VCDClose: closes VCD releasing allocated memory.
1107 *****************************************************************************/
1109 E_(VCDClose) ( vlc_object_t *p_this )
1111 access_t *p_access = (access_t *)p_this;
1112 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_access->p_sys;
1114 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1116 vcdinfo_close( p_vcd->vcd );
1118 free( p_vcd->p_entries );
1119 free( p_vcd->p_segments );
1120 free( p_vcd->p_sectors );
1122 /* For reasons that are a mystery to me we don't have to deal with
1123 stopping, and destroying the p_vcd->p_intf thread. And if we do
1124 it causes problems upstream.
1126 if( p_vcd->p_intf != NULL )
1128 p_vcd->p_intf = NULL;
1132 p_access->p_sys = NULL;
1133 p_vcd_access = NULL;
1136 /*****************************************************************************
1137 * Control: The front-end or vlc engine calls here to ether get
1138 * information such as meta information or plugin capabilities or to
1139 * issue miscellaneous "set" requests.
1140 *****************************************************************************/
1141 static int VCDControl( access_t *p_access, int i_query, va_list args )
1143 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
1147 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1148 "query %d", i_query );
1152 /* Pass back a copy of meta information that was gathered when we
1153 during the Open/Initialize call.
1155 case ACCESS_GET_META:
1157 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1159 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1161 if ( p_vcd->p_meta ) {
1162 *pp_meta = vlc_meta_Duplicate( p_vcd->p_meta );
1163 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1165 msg_Warn( p_access, "tried to copy NULL meta info" );
1169 return VLC_EGENERIC;
1171 case ACCESS_CAN_SEEK:
1172 case ACCESS_CAN_FASTSEEK:
1173 case ACCESS_CAN_PAUSE:
1174 case ACCESS_CAN_CONTROL_PACE:
1176 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1178 dbg_print( INPUT_DBG_EVENT,
1179 "seek/fastseek/pause/can_control_pace" );
1180 *pb_bool = VLC_TRUE;
1186 case ACCESS_GET_MTU:
1187 pi_int = (int*)va_arg( args, int * );
1188 *pi_int = (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE);
1189 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1192 case ACCESS_GET_PTS_DELAY:
1194 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1195 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1196 * MILLISECONDS_PER_SEC;
1197 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1203 case ACCESS_SET_PAUSE_STATE:
1204 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1208 case ACCESS_GET_TITLE_INFO:
1210 input_title_t ***ppp_title;
1213 ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
1214 pi_int = (int*)va_arg( args, int* );
1216 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1219 VCDMetaInfo( p_access );
1221 /* Duplicate title info */
1222 if( p_vcd->i_titles == 0 )
1224 *pi_int = 0; ppp_title = NULL;
1227 *pi_int = p_vcd->i_titles;
1228 *ppp_title = malloc(sizeof( input_title_t **) * p_vcd->i_titles );
1230 if (!*ppp_title) return VLC_ENOMEM;
1232 for( i = 0; i < p_vcd->i_titles; i++ )
1234 if ( p_vcd->p_title[i] )
1236 vlc_input_title_Duplicate( p_vcd->p_title[i] );
1244 case ACCESS_SET_TITLE:
1245 i = (int)va_arg( args, int );
1247 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1248 if( i != p_access->info.i_title )
1251 p_access->info.i_update |=
1252 INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE;
1253 p_access->info.i_title = i;
1254 p_access->info.i_size = p_vcd->p_title[i]->i_size;
1255 p_access->info.i_pos = 0;
1257 /* Next sector to read */
1258 p_vcd->i_lsn = p_vcd->p_sectors[i];
1262 case ACCESS_SET_SEEKPOINT:
1264 input_title_t *t = p_vcd->p_title[p_access->info.i_title];
1265 i = (int)va_arg( args, int );
1266 if( t->i_seekpoint > 0 )
1268 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
1269 p_access->info.i_seekpoint = i;
1271 p_vcd->i_lsn = p_vcd->p_sectors[1+p_access->info.i_title] +
1272 t->seekpoint[i]->i_byte_offset / M2F2_SECTOR_SIZE;
1274 p_access->info.i_pos =
1275 (int64_t)(p_vcd->i_lsn -
1276 p_vcd->p_sectors[1+p_access->info.i_title])
1282 case ACCESS_SET_PRIVATE_ID_STATE:
1283 dbg_print( INPUT_DBG_EVENT, "set seekpoint/set private id" );
1284 return VLC_EGENERIC;
1287 msg_Warn( p_access, "unimplemented query in control" );
1288 return VLC_EGENERIC;