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>
49 /* how many blocks VCDRead will read in each loop */
50 #define VCD_BLOCKS_ONCE 20
52 /*****************************************************************************
54 *****************************************************************************/
56 /* First those which are accessed from outside (via pointers). */
57 static block_t *VCDReadBlock ( access_t * );
59 static int VCDControl ( access_t *p_access, int i_query,
62 /* Now those which are strictly internal */
63 static void VCDSetOrigin ( access_t *p_access,
65 lsn_t i_lsn, lsn_t end_lsn,
67 const vcdinfo_itemid_t * p_itemid );
68 static int VCDEntryPoints ( access_t * );
69 static int VCDLIDs ( access_t * );
71 static int VCDSegments ( access_t * );
73 static int VCDTitles ( access_t * );
74 static int VCDReadSector ( vlc_object_t *p_this,
75 const vcdinfo_obj_t *p_vcd, lsn_t i_lsn,
77 static char *VCDParse ( access_t *,
78 /*out*/ vcdinfo_itemid_t * p_itemid ,
79 /*out*/ vlc_bool_t *play_single_item );
81 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
82 const char *p_varname, char *p_label,
83 const char *p_debug_label );
85 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
87 /****************************************************************************
89 ****************************************************************************/
91 /* FIXME: This variable is a hack. Would be nice to eliminate the
94 static access_t *p_vcd_access = NULL;
96 /* process messages that originate from libcdio. */
98 cdio_log_handler (cdio_log_level_t level, const char message[])
100 const access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
104 if (p_vcd->i_debug & INPUT_DBG_CDIO)
105 msg_Dbg( p_vcd_access, message);
108 msg_Warn( p_vcd_access, message);
111 case CDIO_LOG_ASSERT:
112 msg_Err( p_vcd_access, message);
115 msg_Warn( p_vcd_access, message,
116 _("The above message had unknown log level"),
122 /* process messages that originate from vcdinfo. */
124 vcd_log_handler (vcd_log_level_t level, const char message[])
126 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
130 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
131 msg_Dbg( p_vcd_access, message);
134 msg_Warn( p_vcd_access, message);
138 msg_Err( p_vcd_access, message);
141 msg_Warn( p_vcd_access, "%s\n%s %d", message,
142 _("The above message had unknown vcdimager log level"),
148 /*****************************************************************************
149 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
150 NULL is returned if something went wrong.
151 *****************************************************************************/
153 VCDReadBlock( access_t * p_access )
155 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
157 int i_blocks = VCD_BLOCKS_ONCE;
160 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
164 dbg_print( (INPUT_DBG_CALL), "lsn: %lu",
165 (long unsigned int) p_vcd->i_lsn );
167 /* Compute the number of blocks we have to read */
169 i_blocks = VCD_BLOCKS_ONCE ;
171 /* Allocate a block for the reading */
172 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
174 msg_Err( p_access, "cannot get a new block of size: %i",
175 i_blocks * M2F2_SECTOR_SIZE );
176 block_Release( p_block );
180 for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
183 if ( p_vcd->i_lsn == p_vcd->end_lsn ) {
184 vcdplayer_read_status_t read_status;
186 /* We've run off of the end of this entry. Do we continue or stop? */
187 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
188 "end reached, cur: %lu",
189 (long unsigned int) p_vcd->i_lsn );
191 read_status = vcdplayer_pbc_is_on( p_vcd )
192 ? vcdplayer_pbc_nav( p_access )
193 : vcdplayer_non_pbc_nav( p_access );
195 switch (read_status) {
197 /* End reached. Return NULL to indicated this. */
199 /* Some sort of error. */
202 case READ_STILL_FRAME:
204 /* Reached the end of a still frame. */
205 byte_t * p_buf = (byte_t *) p_block->p_buffer;
207 p_buf += (i_index*M2F2_SECTOR_SIZE);
208 memset(p_buf, 0, M2F2_SECTOR_SIZE);
211 dbg_print(INPUT_DBG_STILL, "Handled still event");
213 p_vcd->p_intf->p_sys->b_still = VLC_TRUE;
214 var_SetInteger( p_access, "state", PAUSE_S );
224 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
226 (byte_t *) p_block->p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
228 LOG_ERR ("could not read sector %lu",
229 (long unsigned int) p_vcd->i_lsn );
237 if ( i_index != i_blocks ) /* this should not happen */
239 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
240 p_vcd->i_lsn, p_last_sector ) < 0 )
242 LOG_ERR ("could not read sector %lu",
243 (long unsigned int) p_vcd->i_lsn );
249 /* Update seekpoints */
250 for( i_read = 0; i_read < i_blocks; i_read++ )
252 input_title_t *t = p_vcd->p_title[p_access->info.i_title];
254 if( t->i_seekpoint > 0 &&
255 p_access->info.i_seekpoint + 1 < t->i_seekpoint &&
256 p_access->info.i_pos + i_read * M2F2_SECTOR_SIZE >=
257 t->seekpoint[p_access->info.i_seekpoint+1]->i_byte_offset )
259 msg_Dbg( p_access, "seekpoint change" );
260 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
261 p_access->info.i_seekpoint++;
265 /* Update a few values */
266 p_vcd->i_lsn += i_blocks;
267 p_access->info.i_pos += p_block->i_buffer;
273 /****************************************************************************
275 ****************************************************************************/
277 VCDSeek( access_t * p_access, int64_t i_pos )
279 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
282 access_vcd_data_t *p_vcd =
283 (access_vcd_data_t *)p_vcd_access->p_sys;
284 const input_title_t *t = p_vcd->p_title[p_access->info.i_title];
286 unsigned int i_entry=VCDINFO_INVALID_ENTRY;
288 /* Next sector to read */
289 p_access->info.i_pos = i_pos;
290 p_vcd->i_lsn = (i_pos / (int64_t)M2F2_SECTOR_SIZE) +
294 if( p_vcd->b_valid_ep )
296 for( i_entry = 0 ; i_entry < p_vcd->i_entries ; i_entry ++ )
298 if( p_vcd->i_lsn < p_vcd->p_entries[i_entry] )
300 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
301 "chapter", _("Entry"), "Setting entry" );
305 p_vcd->play_item.num = i_entry;
306 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
310 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
312 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
313 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
316 /* Update current seekpoint */
317 if( i_seekpoint != p_access->info.i_seekpoint )
319 msg_Dbg( p_access, "seekpoint change" );
320 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
321 p_access->info.i_seekpoint = i_seekpoint;
324 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
325 "orig %lu, cur: %lu, offset: %lld, entry %d",
326 (long unsigned int) p_vcd->origin_lsn,
327 (long unsigned int) p_vcd->i_lsn, i_pos,
335 /*****************************************************************************
336 VCDPlay: set up internal structures so seeking/reading places an item.
337 itemid: the thing to play.
338 user_entry: true if itemid is a user selection (rather than internally-
339 generated selection such as via PBC) in which case we may have to adjust
340 for differences in numbering.
341 *****************************************************************************/
343 VCDPlay( access_t *p_access, vcdinfo_itemid_t itemid )
345 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
349 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
351 const vlc_bool_t b_was_still = p_vcd->in_still;
354 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
355 itemid.num, itemid.type);
357 switch (itemid.type) {
358 case VCDINFO_ITEM_TYPE_TRACK:
361 track_t i_track = itemid.num;
362 unsigned int i_entry =
363 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
365 /* Valid tracks go from 1...i_tracks-1, because track 0 is
368 if (i_track == 0 || i_track >= p_vcd->i_tracks) {
369 LOG_ERR ("Invalid track number %d", i_track );
372 p_vcd->in_still = VLC_FALSE;
373 VCDSetOrigin( p_access,
374 vcdinfo_get_track_lsn(p_vcd->vcd, i_track),
375 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
376 vcdinfo_get_track_lsn(p_vcd->vcd, i_track+1),
381 case VCDINFO_ITEM_TYPE_SEGMENT:
383 int i_seg = itemid.num;
385 /* Valid segments go from 0...i_segments-1. */
386 if (itemid.num >= p_vcd->i_segments) {
387 LOG_ERR ( "Invalid segment number: %d", i_seg );
390 vcdinfo_video_segment_type_t segtype =
391 vcdinfo_get_video_type(p_vcd->vcd, i_seg);
393 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
394 vcdinfo_video_type2str(p_vcd->vcd, i_seg),
395 (int) segtype, itemid.num);
399 case VCDINFO_FILES_VIDEO_NTSC_STILL:
400 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
401 case VCDINFO_FILES_VIDEO_PAL_STILL:
402 case VCDINFO_FILES_VIDEO_PAL_STILL2:
403 p_vcd->in_still = VLC_TRUE;
406 p_vcd->in_still = VLC_FALSE;
408 VCDSetOrigin( p_access, p_vcd->p_segments[i_seg],
409 p_vcd->p_segments[i_seg],
410 p_vcd->p_segments[i_seg+1],
417 case VCDINFO_ITEM_TYPE_LID:
418 /* LIDs go from 1..i_lids. */
419 if (itemid.num == 0 || itemid.num > p_vcd->i_lids) {
420 LOG_ERR ( "Invalid LID number: %d", itemid.num );
423 p_vcd->i_lid = itemid.num;
424 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
426 switch (p_vcd->pxd.descriptor_type) {
428 case PSD_TYPE_SELECTION_LIST:
429 case PSD_TYPE_EXT_SELECTION_LIST: {
430 vcdinfo_itemid_t trans_itemid;
431 uint16_t trans_itemid_num;
433 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
434 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
435 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
436 p_vcd->loop_count = 1;
437 p_vcd->loop_item = trans_itemid;
438 return VCDPlay( p_access, trans_itemid );
442 case PSD_TYPE_PLAY_LIST: {
443 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
445 return vcdplayer_inc_play_item(p_access)
446 ? VLC_SUCCESS : VLC_EGENERIC;
450 case PSD_TYPE_END_LIST:
451 case PSD_TYPE_COMMAND_LIST:
458 case VCDINFO_ITEM_TYPE_ENTRY:
460 int i_entry = itemid.num;
462 /* Entries go from 0..i_entries-1. */
463 if (itemid.num >= p_vcd->i_entries) {
464 LOG_ERR ("Invalid entry number: %d", i_entry );
467 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i_entry);
468 p_vcd->in_still = VLC_FALSE;
469 VCDSetOrigin( p_access,
470 vcdinfo_get_entry_lsn(p_vcd->vcd, i_track),
471 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
472 vcdinfo_get_entry_lsn(p_vcd->vcd, 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);
537 (p_vcd->p_entries[i] - vcdinfo_get_track_lsn(p_vcd->vcd, i_track))
540 TAB_APPEND( p_vcd->p_title[i_track-1]->i_seekpoint,
541 p_vcd->p_title[i_track-1]->seekpoint, s );
543 msg_Warn( p_access, "wrong track number found in entry points" );
545 p_vcd->b_valid_ep = VLC_TRUE;
552 /*****************************************************************************
553 * VCDSegments: Reads the information about the segments the disc.
554 *****************************************************************************/
556 VCDSegments( access_t * p_access )
558 access_vcd_data_t * p_vcd;
560 unsigned int i_segments;
563 p_vcd = (access_vcd_data_t *) p_access->p_sys;
564 i_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
566 #define area p_access->stream.pp_areas
568 /* area 0 is reserved for segments. Set Absolute start offset
570 area[0]->i_plugin_data = 0;
571 input_DelArea( p_access, area[0] );
572 input_AddArea( p_access, 0, 0 );
574 area[0]->i_start = (off_t)p_vcd->p_sectors[0]
575 * (off_t)M2F2_SECTOR_SIZE;
576 area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
577 * (off_t)M2F2_SECTOR_SIZE;
579 /* Default Segment */
582 /* i_plugin_data is used to store which entry point is the first
583 of the track (area) */
584 area[0]->i_plugin_data = 0;
586 area[0]->i_part_nb = 0;
588 dbg_print( INPUT_DBG_MRL,
589 "area[0] id: %d, i_start: %lld, i_size: %lld",
590 area[0]->i_id, area[0]->i_start, area[0]->i_size );
592 if (i_segments == 0) return 0;
594 /* We have one additional segment allocated so we can get the size
595 by subtracting seg[i+1] - seg[i].
597 p_vcd->p_segments = malloc( sizeof( lsn_t ) * (i_segments+1) );
598 if( p_vcd->p_segments == NULL )
600 LOG_ERR ("not enough memory for segment treatment" );
604 /* Update the navigation variables without triggering a callback */
605 VCDUpdateVar( p_access, 0, VLC_VAR_SETVALUE, "title", _("Track"),
608 var_Change( p_access, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
610 for( i = 0 ; i < i_segments ; i++ )
612 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
613 area[0]->i_part_nb ++;
614 VCDUpdateVar( p_access, i , VLC_VAR_ADDCHOICE,
615 "chapter", _("Segment"), "Adding segment choice");
620 p_vcd->p_segments[i_segments] = p_vcd->p_segments[i_segments-1]+
621 vcdinfo_get_seg_sector_count(p_vcd->vcd, i_segments-1);
627 /*****************************************************************************
628 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
630 We start area addressing for tracks at 1 since the default area 0
631 is reserved for segments.
632 *****************************************************************************/
634 VCDTitles( access_t * p_access )
636 /* We'll assume a VCD has its first MPEG track
637 cdio_get_first_track_num()+1 could be used if one wanted to be
638 very careful about this. Note: cdio_get_first_track() will give the
639 ISO-9660 track before the MPEG tracks.
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 = 1 ; i <= p_vcd->i_tracks ; i++ )
651 input_title_t *t = p_vcd->p_title[i-1] = vlc_input_title_New();
653 uint32_t i_secsize = vcdinfo_get_track_sect_count( p_vcd->vcd, i );
655 snprintf( psz_track, sizeof(psz_track), "%s%02d", _("Track "),
658 t->i_size = (i_secsize) * (int64_t) M2F2_SECTOR_SIZE;
659 t->psz_name = strdup(psz_track);
661 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld",
671 /*****************************************************************************
672 VCDLIDs: Reads the LIST IDs from the LOT.
673 *****************************************************************************/
675 VCDLIDs( access_t * p_access )
677 access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
679 p_vcd->i_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
680 p_vcd->i_lid = VCDINFO_INVALID_ENTRY;
682 if (vcdinfo_read_psd (p_vcd->vcd)) {
684 vcdinfo_visit_lot (p_vcd->vcd, VLC_FALSE);
688 We need to change libvcdinfo to be more robust when there are
689 problems reading the extended PSD. Given that area-highlighting and
690 selection features in the extended PSD haven't been implemented,
691 it's best then to not try to read this at all.
693 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
694 vcdinfo_visit_lot (p_vcd->vcd, VLC_TRUE);
698 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
699 "num LIDs=%d", p_vcd->i_lids);
704 /*****************************************************************************
705 * VCDParse: parse command line
706 *****************************************************************************/
708 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
709 /*out*/ vlc_bool_t *play_single_item )
711 access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_access->p_sys;
716 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
717 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
719 *play_single_item = VLC_FALSE;
723 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
728 /* On Win32 we want the VCD access plugin to be explicitly requested,
729 * we end up with lots of problems otherwise */
730 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
733 if( !p_access->psz_path )
738 psz_parser = psz_source = strdup( p_access->psz_path );
740 /* Parse input string :
741 * [device][@[type][title]] */
742 while( *psz_parser && *psz_parser != '@' )
747 if( *psz_parser == '@' )
749 /* Found the divide between the source name and the
750 type+entry number. */
757 switch(*psz_parser) {
759 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
761 *play_single_item = VLC_TRUE;
764 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
766 *play_single_item = VLC_FALSE;
769 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
771 *play_single_item = VLC_TRUE;
774 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
776 *play_single_item = VLC_TRUE;
782 num = strtol( psz_parser, &psz_next, 10 );
783 if ( *psz_parser != '\0' && *psz_next == '\0')
789 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
795 /* No source specified, so figure it out. */
796 if( !p_access->psz_access ) return NULL;
798 psz_source = config_GetPsz( p_access, "vcd" );
800 if( !psz_source || 0==strlen(psz_source) ) {
801 /* Scan for a CD-ROM drive with a VCD in it. */
802 char **cd_drives = cdio_get_devices_with_cap( NULL,
803 ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
804 |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
806 if( NULL == cd_drives ) return NULL;
807 if( cd_drives[0] == NULL )
809 cdio_free_device_list( cd_drives );
812 psz_source = strdup( cd_drives[0] );
813 cdio_free_device_list( cd_drives );
817 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
818 "source=%s entry=%d type=%d",
819 psz_source, p_itemid->num, p_itemid->type);
825 Set's start origin subsequent seeks/reads
828 VCDSetOrigin( access_t *p_access, lsn_t origin_lsn,
829 lsn_t i_lsn, lsn_t end_lsn, track_t i_track,
830 const vcdinfo_itemid_t *p_itemid )
832 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
834 unsigned int i_title = i_track - 1; /* For now */
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_title]->i_size;
846 p_access->info.i_pos = ( i_lsn - origin_lsn ) * M2F2_SECTOR_SIZE;
847 p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE;
849 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
850 "origin: %lu, cur_lsn: %lu, end_lsn: %lu, track: %d",
851 (long unsigned int) origin_lsn,
852 (long unsigned int) i_lsn,
853 (long unsigned int) end_lsn, i_track );
855 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
857 p_itemid->type == VCDINFO_ITEM_TYPE_ENTRY ?
858 _("Entry") : _("Segment"),
859 "Setting entry/segment");
862 /*****************************************************************************
863 * vcd_Open: Opens a VCD device or file and returns an opaque handle
864 *****************************************************************************/
865 static vcdinfo_obj_t *
866 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
868 vcdinfo_obj_t *p_vcdobj;
871 if( !psz_dev ) return NULL;
873 actual_dev=strdup(psz_dev);
874 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
884 /****************************************************************************
885 * VCDReadSector: Read a sector (2324 bytes)
886 ****************************************************************************/
888 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
889 lsn_t i_lsn, byte_t * p_buffer )
892 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
893 uint8_t data [M2F2_SECTOR_SIZE];
896 vcdsector_t vcd_sector;
898 if( cdio_read_mode2_sector( vcdinfo_get_cd_image( p_vcd ),
899 &vcd_sector, i_lsn, VLC_TRUE )
902 msg_Warn( p_this, "Could not read LSN %lu",
903 (long unsigned int) i_lsn );
907 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
912 /****************************************************************************
913 Update the "varname" variable to i_num without triggering a callback.
914 ****************************************************************************/
916 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
917 const char *p_varname, char *p_label,
918 const char *p_debug_label)
923 const access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
924 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
928 text.psz_string = p_label;
929 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
931 var_Change( p_access, p_varname, i_action, &val, NULL );
935 /*****************************************************************************
937 *****************************************************************************/
939 E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
940 vlc_value_t oldval, vlc_value_t val, void *p_data )
942 access_vcd_data_t *p_vcd;
944 if (NULL == p_vcd_access) return VLC_EGENERIC;
946 p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
948 if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
949 msg_Dbg( p_vcd_access, "Old debug (x%0x) %d, new debug (x%0x) %d",
950 p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
952 p_vcd->i_debug = val.i_int;
957 /*****************************************************************************
959 read in meta-information about VCD: the number of tracks, segments,
960 entries, size and starting information. Then set up state variables so
961 that we read/seek starting at the location specified.
963 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
964 and VLC_EGENERIC for some other error.
965 *****************************************************************************/
967 E_(VCDOpen) ( vlc_object_t *p_this )
969 access_t * p_access = (access_t *)p_this;
970 access_vcd_data_t * p_vcd;
972 vcdinfo_itemid_t itemid;
973 vlc_bool_t b_play_ok;
974 vlc_bool_t play_single_item = VLC_FALSE;
976 p_access->pf_read = NULL;
977 p_access->pf_block = VCDReadBlock;
978 p_access->pf_control = VCDControl;
979 p_access->pf_seek = VCDSeek;
981 p_access->info.i_update = 0;
982 p_access->info.i_size = 0;
983 p_access->info.i_pos = 0;
984 p_access->info.b_eof = VLC_FALSE;
985 p_access->info.i_title = 0;
986 p_access->info.i_seekpoint = 0;
988 p_vcd = malloc( sizeof(access_vcd_data_t) );
992 LOG_ERR ("out of memory" );
996 p_access->p_sys = (access_sys_t *) p_vcd;
998 /* Set where to log errors messages from libcdio. */
999 p_vcd_access = p_access;
1000 cdio_log_set_handler ( cdio_log_handler );
1001 vcd_log_set_handler ( vcd_log_handler );
1003 psz_source = VCDParse( p_access, &itemid, &play_single_item );
1005 if ( NULL == psz_source )
1008 return( VLC_EGENERIC );
1011 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1012 psz_source, p_access->psz_path );
1014 p_vcd->psz_source = strdup(psz_source);
1015 p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
1016 p_vcd->in_still = VLC_FALSE;
1017 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
1018 p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT,
1020 p_vcd->p_meta = vlc_meta_New();
1021 p_vcd->p_segments = NULL;
1022 p_vcd->p_entries = NULL;
1026 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1028 msg_Warn( p_access, "could not open %s", psz_source );
1032 p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
1034 /* Get track information. */
1035 p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcd->vcd);
1037 if( p_vcd->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcd->i_tracks ) {
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->psz_source );
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 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1211 + strlen(p_vcd->psz_source) + sizeof("@E999")+3;
1212 input_title_t ***ppp_title
1213 = (input_title_t***)va_arg( args, input_title_t*** );
1214 char *psz_mrl = malloc( psz_mrl_max );
1217 pi_int = (int*)va_arg( args, int* );
1219 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1222 if( psz_mrl == NULL ) {
1223 msg_Warn( p_access, "out of memory" );
1225 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1226 VCD_MRL_PREFIX, p_vcd->psz_source);
1227 VCDMetaInfo( p_access, psz_mrl );
1231 /* Duplicate title info */
1232 if( p_vcd->i_titles == 0 )
1234 *pi_int = 0; ppp_title = NULL;
1237 *pi_int = p_vcd->i_titles;
1238 *ppp_title = malloc(sizeof( input_title_t **) * p_vcd->i_titles );
1240 if (!*ppp_title) return VLC_ENOMEM;
1242 for( i = 0; i < p_vcd->i_titles; i++ )
1244 if ( p_vcd->p_title[i] )
1246 vlc_input_title_Duplicate( p_vcd->p_title[i] );
1254 case ACCESS_SET_TITLE:
1255 i = (int)va_arg( args, int );
1257 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1258 if( i != p_access->info.i_title )
1260 vcdinfo_itemid_t itemid;
1261 track_t i_track = i+1;
1262 unsigned int i_entry =
1263 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
1265 /* FIXME! For now we are assuming titles are only
1266 tracks and that track == title+1 */
1267 itemid.num = i_track;
1268 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1270 VCDSetOrigin(p_access,
1271 vcdinfo_get_track_lsn(p_vcd->vcd, i_track),
1272 vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
1273 vcdinfo_get_track_lsn(p_vcd->vcd, i_track+1),
1278 case ACCESS_SET_SEEKPOINT:
1280 input_title_t *t = p_vcd->p_title[p_access->info.i_title];
1281 i = (int)va_arg( args, int );
1282 if( t->i_seekpoint > 0 )
1284 track_t i_track = p_access->info.i_title+1;
1285 lsn_t track_lsn = vcdinfo_get_track_lsn(p_vcd->vcd, i_track);
1287 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
1288 p_access->info.i_seekpoint = i;
1290 /* FIXME! For now we are assuming titles are only
1291 tracks and that track == title+1 */
1293 p_vcd->i_lsn = track_lsn
1294 + (t->seekpoint[i]->i_byte_offset / M2F2_SECTOR_SIZE);
1296 p_access->info.i_pos = (int64_t)(p_vcd->i_lsn - track_lsn)
1302 case ACCESS_SET_PRIVATE_ID_STATE:
1303 dbg_print( INPUT_DBG_EVENT, "set seekpoint/set private id" );
1304 return VLC_EGENERIC;
1307 msg_Warn( p_access, "unimplemented query in control" );
1308 return VLC_EGENERIC;