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>
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 /* how many blocks VCDRead will read in each loop */
49 #define VCD_BLOCKS_ONCE 20
51 /*****************************************************************************
53 *****************************************************************************/
55 /* First those which are accessed from outside (via pointers). */
56 static block_t *VCDReadBlock ( access_t * );
58 static int VCDControl ( access_t *p_access, int i_query,
61 /* Now those which are strictly internal */
62 static void VCDSetOrigin ( access_t *p_access,
64 lsn_t i_lsn, lsn_t end_lsn,
66 const vcdinfo_itemid_t * p_itemid );
67 static int VCDEntryPoints ( access_t * );
68 static int VCDLIDs ( access_t * );
70 static int VCDSegments ( access_t * );
72 static int VCDTitles ( access_t * );
73 static int VCDReadSector ( vlc_object_t *p_this,
74 const vcdinfo_obj_t *p_vcd, lsn_t i_lsn,
76 static char *VCDParse ( access_t *,
77 /*out*/ vcdinfo_itemid_t * p_itemid ,
78 /*out*/ vlc_bool_t *play_single_item );
80 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
81 const char *p_varname, char *p_label,
82 const char *p_debug_label );
84 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
86 /****************************************************************************
88 ****************************************************************************/
90 /* FIXME: This variable is a hack. Would be nice to eliminate the
93 static access_t *p_vcd_access = NULL;
95 /* process messages that originate from libcdio. */
97 cdio_log_handler (cdio_log_level_t level, const char message[])
99 const access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
103 if (p_vcd->i_debug & INPUT_DBG_CDIO)
104 msg_Dbg( p_vcd_access, message);
107 msg_Warn( p_vcd_access, message);
110 case CDIO_LOG_ASSERT:
111 msg_Err( p_vcd_access, message);
114 msg_Warn( p_vcd_access, message,
115 _("The above message had unknown log level"),
121 /* process messages that originate from vcdinfo. */
123 vcd_log_handler (vcd_log_level_t level, const char message[])
125 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
129 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
130 msg_Dbg( p_vcd_access, message);
133 msg_Warn( p_vcd_access, message);
137 msg_Err( p_vcd_access, message);
140 msg_Warn( p_vcd_access, "%s\n%s %d", message,
141 _("The above message had unknown vcdimager log level"),
147 /*****************************************************************************
148 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
149 NULL is returned if something went wrong.
150 *****************************************************************************/
152 VCDReadBlock( access_t * p_access )
154 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
156 int i_blocks = VCD_BLOCKS_ONCE;
159 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
163 dbg_print( (INPUT_DBG_CALL), "lsn: %lu",
164 (long unsigned int) p_vcd->i_lsn );
166 /* Compute the number of blocks we have to read */
168 i_blocks = VCD_BLOCKS_ONCE ;
170 /* Allocate a block for the reading */
171 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
173 msg_Err( p_access, "cannot get a new block of size: %i",
174 i_blocks * M2F2_SECTOR_SIZE );
175 block_Release( p_block );
179 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
182 if ( p_vcd->i_lsn == p_vcd->end_lsn ) {
183 vcdplayer_read_status_t read_status;
185 /* We've run off of the end of this entry. Do we continue or stop? */
186 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
187 "end reached, cur: %lu",
188 (long unsigned int) p_vcd->i_lsn );
190 read_status = vcdplayer_pbc_is_on( p_vcd )
191 ? vcdplayer_pbc_nav( p_access )
192 : vcdplayer_non_pbc_nav( p_access );
194 switch (read_status) {
196 /* End reached. Return NULL to indicated this. */
198 /* Some sort of error. */
201 case READ_STILL_FRAME:
203 /* Reached the end of a still frame. */
204 byte_t * p_buf = (byte_t *) p_block->p_buffer;
206 p_buf += (i_index*M2F2_SECTOR_SIZE);
207 memset(p_buf, 0, M2F2_SECTOR_SIZE);
210 dbg_print(INPUT_DBG_STILL, "Handled still event");
212 p_vcd->p_intf->p_sys->b_still = VLC_TRUE;
213 var_SetInteger( p_access, "state", PAUSE_S );
223 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
225 (byte_t *) p_block->p_buffer
226 + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
228 LOG_ERR ("could not read sector %lu",
229 (long unsigned int) p_vcd->i_lsn );
230 /* Try to skip one sector (in case of bad sectors) */
232 p_access->info.i_pos += M2F2_SECTOR_SIZE;
237 p_access->info.i_pos += M2F2_SECTOR_SIZE;
239 /* Update seekpoint */
240 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type )
242 const input_title_t *t = p_vcd->p_title[p_access->info.i_title];
244 if( t->i_seekpoint > 0 &&
245 p_access->info.i_seekpoint + 1 < t->i_seekpoint &&
246 p_access->info.i_pos + i_read * M2F2_SECTOR_SIZE >=
247 t->seekpoint[p_access->info.i_seekpoint+1]->i_byte_offset )
249 const track_t i_track = p_vcd->i_track;
250 const unsigned int i_entry = ++p_vcd->play_item.num;
251 msg_Dbg( p_access, "seekpoint change" );
252 VCDSetOrigin( p_access,
253 vcdinfo_get_track_lsn(p_vcd->vcd, i_track),
254 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
255 vcdinfo_get_track_lsn(p_vcd->vcd, i_track+1),
256 i_track, &(p_vcd->play_item) );
261 if ( i_index != i_blocks ) /* this should not happen */
263 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
264 p_vcd->i_lsn, p_last_sector ) < 0 )
266 LOG_ERR ("could not read sector %lu",
267 (long unsigned int) p_vcd->i_lsn );
278 /****************************************************************************
280 ****************************************************************************/
282 VCDSeek( access_t * p_access, int64_t i_pos )
284 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
287 access_vcd_data_t *p_vcd =
288 (access_vcd_data_t *)p_vcd_access->p_sys;
289 const input_title_t *t = p_vcd->p_title[p_access->info.i_title];
291 unsigned int i_entry=VCDINFO_INVALID_ENTRY;
293 /* Next sector to read */
294 p_access->info.i_pos = i_pos;
295 p_vcd->i_lsn = (i_pos / (int64_t)M2F2_SECTOR_SIZE) +
299 if( p_vcd->b_valid_ep )
301 for( i_entry = 0 ; i_entry < p_vcd->i_entries ; i_entry ++ )
303 if( p_vcd->i_lsn < p_vcd->p_entries[i_entry] )
305 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
306 "chapter", _("Entry"), "Setting entry" );
310 p_vcd->play_item.num = i_entry;
311 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
315 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
317 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
318 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
321 /* Update current seekpoint */
322 if( i_seekpoint != p_access->info.i_seekpoint )
324 msg_Dbg( p_access, "seekpoint change" );
325 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
326 p_access->info.i_seekpoint = i_seekpoint;
329 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
330 "orig %lu, cur: %lu, offset: %lld, entry %d",
331 (long unsigned int) p_vcd->origin_lsn,
332 (long unsigned int) p_vcd->i_lsn, i_pos,
340 /*****************************************************************************
341 VCDPlay: set up internal structures so seeking/reading places an item.
342 itemid: the thing to play.
343 user_entry: true if itemid is a user selection (rather than internally-
344 generated selection such as via PBC) in which case we may have to adjust
345 for differences in numbering.
346 *****************************************************************************/
348 VCDPlay( access_t *p_access, vcdinfo_itemid_t itemid )
350 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
354 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
356 const vlc_bool_t b_was_still = p_vcd->in_still;
359 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
360 itemid.num, itemid.type);
362 switch (itemid.type) {
363 case VCDINFO_ITEM_TYPE_TRACK:
366 track_t i_track = itemid.num;
367 unsigned int i_entry =
368 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
370 /* Valid tracks go from 1...i_tracks-1, because track 0 is
373 if (i_track == 0 || i_track >= p_vcd->i_tracks) {
374 LOG_ERR ("Invalid track number %d", i_track );
377 p_vcd->in_still = VLC_FALSE;
378 VCDSetOrigin( p_access,
379 vcdinfo_get_track_lsn(p_vcd->vcd, i_track),
380 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
381 vcdinfo_get_track_lsn(p_vcd->vcd, i_track+1),
386 case VCDINFO_ITEM_TYPE_SEGMENT:
388 int i_seg = itemid.num;
390 /* Valid segments go from 0...i_segments-1. */
391 if (itemid.num >= p_vcd->i_segments) {
392 LOG_ERR ( "Invalid segment number: %d", i_seg );
395 vcdinfo_video_segment_type_t segtype =
396 vcdinfo_get_video_type(p_vcd->vcd, i_seg);
398 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
399 vcdinfo_video_type2str(p_vcd->vcd, i_seg),
400 (int) segtype, itemid.num);
404 case VCDINFO_FILES_VIDEO_NTSC_STILL:
405 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
406 case VCDINFO_FILES_VIDEO_PAL_STILL:
407 case VCDINFO_FILES_VIDEO_PAL_STILL2:
408 p_vcd->in_still = VLC_TRUE;
411 p_vcd->in_still = VLC_FALSE;
413 VCDSetOrigin( p_access, p_vcd->p_segments[i_seg],
414 p_vcd->p_segments[i_seg],
415 p_vcd->p_segments[i_seg+1],
422 case VCDINFO_ITEM_TYPE_LID:
423 /* LIDs go from 1..i_lids. */
424 if (itemid.num == 0 || itemid.num > p_vcd->i_lids) {
425 LOG_ERR ( "Invalid LID number: %d", itemid.num );
428 p_vcd->i_lid = itemid.num;
429 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
431 switch (p_vcd->pxd.descriptor_type) {
433 case PSD_TYPE_SELECTION_LIST:
434 case PSD_TYPE_EXT_SELECTION_LIST: {
435 vcdinfo_itemid_t trans_itemid;
436 uint16_t trans_itemid_num;
438 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
439 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
440 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
441 p_vcd->loop_count = 1;
442 p_vcd->loop_item = trans_itemid;
443 return VCDPlay( p_access, trans_itemid );
447 case PSD_TYPE_PLAY_LIST: {
448 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
450 return vcdplayer_inc_play_item(p_access)
451 ? VLC_SUCCESS : VLC_EGENERIC;
455 case PSD_TYPE_END_LIST:
456 case PSD_TYPE_COMMAND_LIST:
463 case VCDINFO_ITEM_TYPE_ENTRY:
465 int i_entry = itemid.num;
467 /* Entries go from 0..i_entries-1. */
468 if (itemid.num >= p_vcd->i_entries) {
469 LOG_ERR ("Invalid entry number: %d", i_entry );
472 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i_entry);
473 p_vcd->in_still = VLC_FALSE;
474 VCDSetOrigin( p_access,
475 vcdinfo_get_entry_lsn(p_vcd->vcd, i_track),
476 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
477 vcdinfo_get_entry_lsn(p_vcd->vcd, i_track+1),
484 LOG_ERR ("unknown entry type" );
488 p_vcd->play_item = itemid;
496 /*****************************************************************************
497 VCDEntryPoints: Reads the information about the entry points on the disc
498 and initializes area information with that.
499 Before calling this track information should have been read in.
500 *****************************************************************************/
502 VCDEntryPoints( access_t * p_access )
504 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
507 access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
508 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcd->vcd);
509 const track_t i_last_track
510 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcd->vcd))
511 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcd->vcd));
514 if (0 == i_entries) {
515 LOG_ERR ("no entires found -- something is wrong" );
519 p_vcd->p_entries = malloc( sizeof( lsn_t ) * i_entries );
521 if( p_vcd->p_entries == NULL )
523 LOG_ERR ("not enough memory for entry points treatment" );
527 p_vcd->i_entries = i_entries;
529 for( i = 0 ; i < i_entries ; i++ )
531 const track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
532 if( i_track <= i_last_track ) {
533 seekpoint_t *s = vlc_seekpoint_New();
536 snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
538 p_vcd->p_entries[i] = vcdinfo_get_entry_lsn(p_vcd->vcd, i);
540 s->psz_name = strdup(psz_entry);
542 (p_vcd->p_entries[i] - vcdinfo_get_track_lsn(p_vcd->vcd, i_track))
545 TAB_APPEND( p_vcd->p_title[i_track-1]->i_seekpoint,
546 p_vcd->p_title[i_track-1]->seekpoint, s );
548 msg_Warn( p_access, "wrong track number found in entry points" );
550 p_vcd->b_valid_ep = VLC_TRUE;
557 /*****************************************************************************
558 * VCDSegments: Reads the information about the segments the disc.
559 *****************************************************************************/
561 VCDSegments( access_t * p_access )
563 access_vcd_data_t * p_vcd;
565 unsigned int i_segments;
568 p_vcd = (access_vcd_data_t *) p_access->p_sys;
569 i_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
571 #define area p_access->stream.pp_areas
573 /* area 0 is reserved for segments. Set Absolute start offset
575 area[0]->i_plugin_data = 0;
576 input_DelArea( p_access, area[0] );
577 input_AddArea( p_access, 0, 0 );
579 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
580 * (off_t)M2F2_SECTOR_SIZE;
581 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
582 * (off_t)M2F2_SECTOR_SIZE;
584 /* Default Segment */
587 /* i_plugin_data is used to store which entry point is the first
588 of the track (area) */
589 area[0]->i_plugin_data = 0;
591 area[0]->i_part_nb = 0;
593 dbg_print( INPUT_DBG_MRL,
594 "area[0] id: %d, i_start: %lld, i_size: %lld",
595 area[0]->i_id, area[0]->i_start, area[0]->i_size );
597 if (i_segments == 0) return 0;
599 /* We have one additional segment allocated so we can get the size
600 by subtracting seg[i+1] - seg[i].
602 p_vcd->p_segments = malloc( sizeof( lsn_t ) * (i_segments+1) );
603 if( p_vcd->p_segments == NULL )
605 LOG_ERR ("not enough memory for segment treatment" );
609 /* Update the navigation variables without triggering a callback */
610 VCDUpdateVar( p_access, 0, VLC_VAR_SETVALUE, "title", _("Track"),
613 var_Change( p_access, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
615 for( i = 0 ; i < i_segments ; i++ )
617 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
618 area[0]->i_part_nb ++;
619 VCDUpdateVar( p_access, i , VLC_VAR_ADDCHOICE,
620 "chapter", _("Segment"), "Adding segment choice");
625 p_vcd->p_segments[i_segments] = p_vcd->p_segments[i_segments-1]+
626 vcdinfo_get_seg_sector_count(p_vcd->vcd, i_segments-1);
632 /*****************************************************************************
633 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
635 We start area addressing for tracks at 1 since the default area 0
636 is reserved for segments.
637 *****************************************************************************/
639 VCDTitles( access_t * p_access )
641 /* We'll assume a VCD has its first MPEG track
642 cdio_get_first_track_num()+1 could be used if one wanted to be
643 very careful about this. Note: cdio_get_first_track() will give the
644 ISO-9660 track before the MPEG tracks.
647 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
650 access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
654 for( i = 1 ; i <= p_vcd->i_tracks ; i++ )
656 input_title_t *t = p_vcd->p_title[i-1] = vlc_input_title_New();
658 uint32_t i_secsize = vcdinfo_get_track_sect_count( p_vcd->vcd, i );
660 snprintf( psz_track, sizeof(psz_track), "%s%02d", _("Track "),
663 t->i_size = (i_secsize) * (int64_t) M2F2_SECTOR_SIZE;
664 t->psz_name = strdup(psz_track);
666 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld",
676 /*****************************************************************************
677 VCDLIDs: Reads the LIST IDs from the LOT.
678 *****************************************************************************/
680 VCDLIDs( access_t * p_access )
682 access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
684 p_vcd->i_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
685 p_vcd->i_lid = VCDINFO_INVALID_ENTRY;
687 if (vcdinfo_read_psd (p_vcd->vcd)) {
689 vcdinfo_visit_lot (p_vcd->vcd, VLC_FALSE);
693 We need to change libvcdinfo to be more robust when there are
694 problems reading the extended PSD. Given that area-highlighting and
695 selection features in the extended PSD haven't been implemented,
696 it's best then to not try to read this at all.
698 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
699 vcdinfo_visit_lot (p_vcd->vcd, VLC_TRUE);
703 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
704 "num LIDs=%d", p_vcd->i_lids);
709 /*****************************************************************************
710 * VCDParse: parse command line
711 *****************************************************************************/
713 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
714 /*out*/ vlc_bool_t *play_single_item )
716 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_access->p_sys;
721 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
722 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
724 *play_single_item = VLC_FALSE;
728 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
733 /* On Win32 we want the VCD access plugin to be explicitly requested,
734 * we end up with lots of problems otherwise */
735 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
738 if( !p_access->psz_path )
743 psz_parser = psz_source = strdup( p_access->psz_path );
745 /* Parse input string :
746 * [device][@[type][title]] */
747 while( *psz_parser && *psz_parser != '@' )
752 if( *psz_parser == '@' )
754 /* Found the divide between the source name and the
755 type+entry number. */
762 switch(*psz_parser) {
764 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
766 *play_single_item = VLC_TRUE;
769 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
771 *play_single_item = VLC_FALSE;
774 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
776 *play_single_item = VLC_TRUE;
779 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
781 *play_single_item = VLC_TRUE;
787 num = strtol( psz_parser, &psz_next, 10 );
788 if ( *psz_parser != '\0' && *psz_next == '\0')
794 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
800 /* No source specified, so figure it out. */
801 if( !p_access->psz_access ) return NULL;
803 psz_source = config_GetPsz( p_access, "vcd" );
805 if( !psz_source || 0==strlen(psz_source) ) {
806 /* Scan for a CD-ROM drive with a VCD in it. */
807 char **cd_drives = cdio_get_devices_with_cap( NULL,
808 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
809 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
811 if( NULL == cd_drives ) return NULL;
812 if( cd_drives[0] == NULL )
814 cdio_free_device_list( cd_drives );
817 psz_source = strdup( cd_drives[0] );
818 cdio_free_device_list( cd_drives );
822 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
823 "source=%s entry=%d type=%d",
824 psz_source, p_itemid->num, p_itemid->type);
830 Set's start origin subsequent seeks/reads
833 VCDSetOrigin( access_t *p_access, lsn_t origin_lsn,
834 lsn_t i_lsn, lsn_t end_lsn, track_t i_track,
835 const vcdinfo_itemid_t *p_itemid )
837 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
839 unsigned int i_title = i_track - 1; /* For now */
841 p_vcd->origin_lsn = origin_lsn;
842 p_vcd->i_lsn = i_lsn;
843 p_vcd->end_lsn = end_lsn;
844 p_vcd->i_track = i_track;
845 p_vcd->play_item.num = p_itemid->num;
846 p_vcd->play_item.type = p_itemid->type;
848 p_access->info.i_title = i_track-1;
849 p_access->info.i_seekpoint = p_itemid->num;
850 p_access->info.i_size = p_vcd->p_title[i_title]->i_size;
851 p_access->info.i_pos = ( i_lsn - origin_lsn ) * M2F2_SECTOR_SIZE;
852 p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
853 | INPUT_UPDATE_SEEKPOINT;
855 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
856 "origin: %lu, cur_lsn: %lu, end_lsn: %lu, track: %d",
857 (long unsigned int) origin_lsn,
858 (long unsigned int) i_lsn,
859 (long unsigned int) end_lsn, i_track );
861 if (p_itemid->type == VCDINFO_ITEM_TYPE_ENTRY) {
862 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
863 "chapter", _("Entry"), "Setting entry/segment");
864 p_access->info.i_seekpoint = p_itemid->num;
866 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
867 "chapter", _("Segment"), "Setting entry/segment");
868 /* seekpoint is what? ??? */
872 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
873 + strlen(p_vcd->psz_source) + sizeof("@E999")+3;
874 char *psz_mrl = malloc( psz_mrl_max );
879 snprintf(psz_mrl, psz_mrl_max, "%s%s",
880 VCD_MRL_PREFIX, p_vcd->psz_source);
881 psz_name = VCDFormatStr( p_access, p_vcd,
882 config_GetPsz( p_access, MODULE_STRING
884 psz_mrl, &(p_vcd->play_item) );
885 input_Control( p_vcd->p_input, INPUT_SET_NAME, psz_name );
892 /*****************************************************************************
893 * vcd_Open: Opens a VCD device or file and returns an opaque handle
894 *****************************************************************************/
895 static vcdinfo_obj_t *
896 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
898 vcdinfo_obj_t *p_vcdobj;
901 if( !psz_dev ) return NULL;
903 actual_dev=strdup(psz_dev);
904 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
914 /****************************************************************************
915 * VCDReadSector: Read a sector (2324 bytes)
916 ****************************************************************************/
918 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
919 lsn_t i_lsn, byte_t * p_buffer )
922 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
923 uint8_t data [M2F2_SECTOR_SIZE];
926 vcdsector_t vcd_sector;
928 if( cdio_read_mode2_sector( vcdinfo_get_cd_image( p_vcd ),
929 &vcd_sector, i_lsn, VLC_TRUE )
932 msg_Warn( p_this, "Could not read LSN %lu",
933 (long unsigned int) i_lsn );
937 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
942 /****************************************************************************
943 Update the "varname" variable to i_num without triggering a callback.
944 ****************************************************************************/
946 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
947 const char *p_varname, char *p_label,
948 const char *p_debug_label)
953 const access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
954 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
958 text.psz_string = p_label;
959 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
961 var_Change( p_access, p_varname, i_action, &val, NULL );
965 /*****************************************************************************
967 *****************************************************************************/
969 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
970 vlc_value_t oldval, vlc_value_t val, void *p_data )
972 access_vcd_data_t *p_vcd;
974 if (NULL == p_vcd_access) return VLC_EGENERIC;
976 p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
978 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
979 msg_Dbg( p_vcd_access, "Old debug (x%0x) %d, new debug (x%0x) %d",
980 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
982 p_vcd->i_debug = val.i_int;
987 /*****************************************************************************
989 read in meta-information about VCD: the number of tracks, segments,
990 entries, size and starting information. Then set up state variables so
991 that we read/seek starting at the location specified.
993 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
994 and VLC_EGENERIC for some other error.
995 *****************************************************************************/
997 E_(VCDOpen) ( vlc_object_t *p_this )
999 access_t * p_access = (access_t *)p_this;
1000 access_vcd_data_t * p_vcd;
1002 vcdinfo_itemid_t itemid;
1003 vlc_bool_t b_play_ok;
1004 vlc_bool_t play_single_item = VLC_FALSE;
1006 p_access->pf_read = NULL;
1007 p_access->pf_block = VCDReadBlock;
1008 p_access->pf_control = VCDControl;
1009 p_access->pf_seek = VCDSeek;
1011 p_access->info.i_update = 0;
1012 p_access->info.i_size = 0;
1013 p_access->info.i_pos = 0;
1014 p_access->info.b_eof = VLC_FALSE;
1015 p_access->info.i_title = 0;
1016 p_access->info.i_seekpoint = 0;
1018 p_vcd = malloc( sizeof(access_vcd_data_t) );
1022 LOG_ERR ("out of memory" );
1026 p_access->p_sys = (access_sys_t *) p_vcd;
1028 /* Set where to log errors messages from libcdio. */
1029 p_vcd_access = p_access;
1030 cdio_log_set_handler ( cdio_log_handler );
1031 vcd_log_set_handler ( vcd_log_handler );
1033 psz_source = VCDParse( p_access, &itemid, &play_single_item );
1035 if ( NULL == psz_source )
1038 return( VLC_EGENERIC );
1041 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1042 psz_source, p_access->psz_path );
1044 p_vcd->psz_source = strdup(psz_source);
1045 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
1046 p_vcd->in_still = VLC_FALSE;
1047 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
1048 p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT,
1050 p_vcd->p_meta = vlc_meta_New();
1051 p_vcd->p_segments = NULL;
1052 p_vcd->p_entries = NULL;
1056 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1058 msg_Warn( p_access, "could not open %s", psz_source );
1062 p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
1064 /* Get track information. */
1065 p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcd->vcd);
1067 if( p_vcd->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcd->i_tracks ) {
1068 vcdinfo_close( p_vcd->vcd );
1069 LOG_ERR ("no movie tracks found" );
1074 /* Initialize segment information. */
1075 VCDSegments( p_access );
1078 /* Build Navigation Title table. */
1079 VCDTitles( p_access );
1081 /* Map entry points into Chapters */
1082 if( VCDEntryPoints( p_access ) < 0 )
1084 msg_Warn( p_access, "could not read entry points, will not use them" );
1085 p_vcd->b_valid_ep = VLC_FALSE;
1088 if( VCDLIDs( p_access ) < 0 )
1090 msg_Warn( p_access, "could not read entry LIDs" );
1093 b_play_ok = (VLC_SUCCESS == VCDPlay( p_access, itemid ));
1095 if ( ! b_play_ok ) {
1096 vcdinfo_close( p_vcd->vcd );
1100 p_access->psz_demux = strdup( "ps" );
1103 p_vcd->p_intf = intf_Create( p_access, "vcdx" );
1104 p_vcd->p_intf->b_block = VLC_FALSE;
1105 intf_RunThread( p_vcd->p_intf );
1109 if (play_single_item)
1110 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
1121 return VLC_EGENERIC;
1124 /*****************************************************************************
1125 * VCDClose: closes VCD releasing allocated memory.
1126 *****************************************************************************/
1128 E_(VCDClose) ( vlc_object_t *p_this )
1130 access_t *p_access = (access_t *)p_this;
1131 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_access->p_sys;
1133 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1135 vcdinfo_close( p_vcd->vcd );
1137 free( p_vcd->p_entries );
1138 free( p_vcd->p_segments );
1139 free( p_vcd->psz_source );
1141 /* For reasons that are a mystery to me we don't have to deal with
1142 stopping, and destroying the p_vcd->p_intf thread. And if we do
1143 it causes problems upstream.
1145 if( p_vcd->p_intf != NULL )
1147 p_vcd->p_intf = NULL;
1151 p_access->p_sys = NULL;
1152 p_vcd_access = NULL;
1155 /*****************************************************************************
1156 * Control: The front-end or vlc engine calls here to ether get
1157 * information such as meta information or plugin capabilities or to
1158 * issue miscellaneous "set" requests.
1159 *****************************************************************************/
1160 static int VCDControl( access_t *p_access, int i_query, va_list args )
1162 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
1166 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1167 "query %d", i_query );
1171 /* Pass back a copy of meta information that was gathered when we
1172 during the Open/Initialize call.
1174 case ACCESS_GET_META:
1176 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1178 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1180 if ( p_vcd->p_meta ) {
1181 *pp_meta = vlc_meta_Duplicate( p_vcd->p_meta );
1182 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1184 msg_Warn( p_access, "tried to copy NULL meta info" );
1188 return VLC_EGENERIC;
1190 case ACCESS_CAN_SEEK:
1191 case ACCESS_CAN_FASTSEEK:
1192 case ACCESS_CAN_PAUSE:
1193 case ACCESS_CAN_CONTROL_PACE:
1195 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1197 dbg_print( INPUT_DBG_EVENT,
1198 "seek/fastseek/pause/can_control_pace" );
1199 *pb_bool = VLC_TRUE;
1205 case ACCESS_GET_MTU:
1206 pi_int = (int*)va_arg( args, int * );
1207 *pi_int = (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE);
1208 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1211 case ACCESS_GET_PTS_DELAY:
1213 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1214 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1215 * MILLISECONDS_PER_SEC;
1216 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1222 case ACCESS_SET_PAUSE_STATE:
1223 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1227 case ACCESS_GET_TITLE_INFO:
1229 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1230 + strlen(p_vcd->psz_source) + sizeof("@E999")+3;
1231 input_title_t ***ppp_title
1232 = (input_title_t***)va_arg( args, input_title_t*** );
1233 char *psz_mrl = malloc( psz_mrl_max );
1236 pi_int = (int*)va_arg( args, int* );
1238 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1241 if( psz_mrl == NULL ) {
1242 msg_Warn( p_access, "out of memory" );
1244 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1245 VCD_MRL_PREFIX, p_vcd->psz_source);
1246 VCDMetaInfo( p_access, psz_mrl );
1250 /* Duplicate title info */
1251 if( p_vcd->i_titles == 0 )
1253 *pi_int = 0; ppp_title = NULL;
1256 *pi_int = p_vcd->i_titles;
1257 *ppp_title = malloc(sizeof( input_title_t **) * p_vcd->i_titles );
1259 if (!*ppp_title) return VLC_ENOMEM;
1261 for( i = 0; i < p_vcd->i_titles; i++ )
1263 if ( p_vcd->p_title[i] )
1265 vlc_input_title_Duplicate( p_vcd->p_title[i] );
1273 case ACCESS_SET_TITLE:
1274 i = (int)va_arg( args, int );
1276 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1277 if( i != p_access->info.i_title )
1279 vcdinfo_itemid_t itemid;
1280 track_t i_track = i+1;
1281 unsigned int i_entry =
1282 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
1284 /* FIXME! For now we are assuming titles are only
1285 tracks and that track == title+1 */
1286 itemid.num = i_track;
1287 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1289 VCDSetOrigin(p_access,
1290 vcdinfo_get_track_lsn(p_vcd->vcd, i_track),
1291 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
1292 vcdinfo_get_track_lsn(p_vcd->vcd, i_track+1),
1297 case ACCESS_SET_SEEKPOINT:
1299 input_title_t *t = p_vcd->p_title[p_access->info.i_title];
1300 i = (int)va_arg( args, int );
1302 dbg_print( INPUT_DBG_EVENT, "set seekpoint" );
1303 if( t->i_seekpoint > 0 )
1305 track_t i_track = p_access->info.i_title+1;
1306 lsn_t track_lsn = vcdinfo_get_track_lsn(p_vcd->vcd, i_track);
1308 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
1309 p_access->info.i_seekpoint = i;
1311 /* FIXME! For now we are assuming titles are only
1312 tracks and that track == title+1 */
1314 p_vcd->i_lsn = track_lsn
1315 + (t->seekpoint[i]->i_byte_offset / M2F2_SECTOR_SIZE);
1317 p_access->info.i_pos = (int64_t)(p_vcd->i_lsn - track_lsn)
1323 case ACCESS_SET_PRIVATE_ID_STATE:
1324 dbg_print( INPUT_DBG_EVENT, "set private id" );
1325 return VLC_EGENERIC;
1328 msg_Warn( p_access, "unimplemented query in control" );
1329 return VLC_EGENERIC;