1 /*****************************************************************************
2 * vcd.c : VCD input module for vlc using libcdio, libvcd and libvcdinfo.
3 * vlc-specific things tend to go here.
4 *****************************************************************************
5 * Copyright (C) 2000, 2003, 2004 VideoLAN
8 * Authors: Rocky Bernstein <rocky@panix.com>
9 * Some code is based on the non-libcdio VCD plugin (as there really
10 * isn't real developer documentation yet on how to write a
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
34 #include <vlc/input.h>
41 #include <cdio/cdio.h>
42 #include <cdio/cd_types.h>
43 #include <cdio/logging.h>
44 #include <cdio/util.h>
45 #include <libvcd/info.h>
46 #include <libvcd/logging.h>
48 #define FREE_AND_NULL(ptr) if (NULL != ptr) free(ptr); ptr = NULL;
50 /*****************************************************************************
52 *****************************************************************************/
54 /* First those which are accessed from outside (via pointers). */
55 static block_t *VCDReadBlock ( access_t * );
57 static int VCDControl ( access_t *p_access, int i_query,
60 /* Now those which are strictly internal */
61 static void VCDSetOrigin ( access_t *p_access, lsn_t i_lsn,
63 const vcdinfo_itemid_t * p_itemid );
64 static vlc_bool_t VCDEntryPoints ( access_t * );
65 static vlc_bool_t VCDLIDs ( access_t * );
66 static vlc_bool_t VCDSegments ( access_t * );
67 static int VCDTitles ( access_t * );
68 static int VCDReadSector ( vlc_object_t *p_this,
69 const vcdinfo_obj_t *p_vcd, lsn_t i_lsn,
71 static char *VCDParse ( access_t *,
72 /*out*/ vcdinfo_itemid_t * p_itemid ,
73 /*out*/ vlc_bool_t *play_single_item );
75 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
76 const char *p_varname, char *p_label,
77 const char *p_debug_label );
79 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
81 /****************************************************************************
83 ****************************************************************************/
85 /* FIXME: This variable is a hack. Would be nice to eliminate the
88 static access_t *p_vcd_access = NULL;
90 /* process messages that originate from libcdio. */
92 cdio_log_handler (cdio_log_level_t level, const char message[])
94 const vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
98 if (p_vcd->i_debug & INPUT_DBG_CDIO)
99 msg_Dbg( p_vcd_access, message);
102 msg_Warn( p_vcd_access, message);
105 case CDIO_LOG_ASSERT:
106 msg_Err( p_vcd_access, message);
109 msg_Warn( p_vcd_access, message,
110 _("The above message had unknown log level"),
116 /* process messages that originate from vcdinfo. */
118 vcd_log_handler (vcd_log_level_t level, const char message[])
120 vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
124 if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
125 msg_Dbg( p_vcd_access, message);
128 msg_Warn( p_vcd_access, message);
132 msg_Err( p_vcd_access, message);
135 msg_Warn( p_vcd_access, "%s\n%s %d", message,
136 _("The above message had unknown vcdimager log level"),
142 /*****************************************************************************
143 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
144 NULL is returned if something went wrong.
145 *****************************************************************************/
147 VCDReadBlock( access_t * p_access )
149 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
151 const int i_blocks = p_vcd->i_blocks_per_read;
153 byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
158 dbg_print( (INPUT_DBG_CALL), "lsn: %lu",
159 (long unsigned int) p_vcd->i_lsn );
162 /* Allocate a block for the reading */
163 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
165 msg_Err( p_access, "cannot get a new block of size: %i",
166 i_blocks * M2F2_SECTOR_SIZE );
167 block_Release( p_block );
171 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
174 if ( p_vcd->i_lsn >= p_vcd->end_lsn ) {
175 vcdplayer_read_status_t read_status;
177 /* We've run off of the end of this entry. Do we continue or stop? */
178 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
179 "end reached, cur: %lu, end: %u",
180 (long unsigned int) p_vcd->i_lsn,
183 read_status = vcdplayer_pbc_is_on( p_vcd )
184 ? vcdplayer_pbc_nav( p_access )
185 : vcdplayer_non_pbc_nav( p_access );
187 switch (read_status) {
189 /* End reached. Return NULL to indicated this. */
191 /* Some sort of error. */
194 case READ_STILL_FRAME:
196 /* Reached the end of a still frame. */
197 byte_t * p_buf = (byte_t *) p_block->p_buffer;
199 p_buf += (i_read*M2F2_SECTOR_SIZE);
200 memset(p_buf, 0, M2F2_SECTOR_SIZE);
203 dbg_print(INPUT_DBG_STILL, "Handled still event");
205 p_vcd->in_still = VLC_TRUE;
206 var_SetInteger( p_access, "state", PAUSE_S );
216 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
218 (byte_t *) p_block->p_buffer
219 + (i_read*M2F2_SECTOR_SIZE) ) < 0 )
221 LOG_ERR ("could not read sector %lu",
222 (long unsigned int) p_vcd->i_lsn );
223 /* Try to skip one sector (in case of bad sectors) */
225 p_access->info.i_pos += M2F2_SECTOR_SIZE;
230 p_access->info.i_pos += M2F2_SECTOR_SIZE;
232 /* Update seekpoint */
233 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type )
235 unsigned int i_entry = p_vcd->play_item.num+1;
237 if (p_vcd->i_lsn >= vcdinfo_get_entry_lba(p_vcd->vcd, i_entry))
239 const track_t i_track = p_vcd->i_track;
240 p_vcd->play_item.num = i_entry;
241 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "entry change" );
242 VCDSetOrigin( p_access,
243 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
244 i_track, &(p_vcd->play_item) );
249 if ( i_read != i_blocks ) /* this should not happen */
251 if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
252 p_vcd->i_lsn, p_last_sector ) < 0 )
254 LOG_ERR ("could not read sector %lu",
255 (long unsigned int) p_vcd->i_lsn );
266 /****************************************************************************
268 ****************************************************************************/
270 VCDSeek( access_t * p_access, int64_t i_pos )
272 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
275 vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
276 const input_title_t *t = p_vcd->p_title[p_access->info.i_title];
278 unsigned int i_entry=VCDINFO_INVALID_ENTRY;
280 /* Next sector to read */
281 p_access->info.i_pos = i_pos;
282 p_vcd->i_lsn = (i_pos / (int64_t)M2F2_SECTOR_SIZE) +
286 if( p_vcd->b_valid_ep )
288 for( i_entry = 0 ; i_entry < p_vcd->i_entries ; i_entry ++ )
290 if( p_vcd->i_lsn < p_vcd->p_entries[i_entry] )
292 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
293 "chapter", _("Entry"), "Setting entry" );
297 p_vcd->play_item.num = i_entry;
298 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
299 vcdplayer_set_origin(p_access);
300 VCDUpdateTitle(p_access);
303 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
304 "orig %lu, cur: %lu, offset: %lld, entry %d",
305 (long unsigned int) p_vcd->origin_lsn,
306 (long unsigned int) p_vcd->i_lsn, i_pos,
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 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
320 (long unsigned int) i_seekpoint );
321 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
322 p_access->info.i_seekpoint = i_seekpoint;
330 /*****************************************************************************
331 VCDPlay: set up internal structures so seeking/reading places an item.
332 itemid: the thing to play.
333 user_entry: true if itemid is a user selection (rather than internally-
334 generated selection such as via PBC) in which case we may have to adjust
335 for differences in numbering.
336 *****************************************************************************/
338 VCDPlay( access_t *p_access, vcdinfo_itemid_t itemid )
340 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
344 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
346 const vlc_bool_t b_was_still = p_vcd->in_still;
349 dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
350 itemid.num, itemid.type);
352 switch (itemid.type) {
353 case VCDINFO_ITEM_TYPE_TRACK:
356 track_t i_track = itemid.num;
357 unsigned int i_entry =
358 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
360 /* Valid MPEG tracks go from 1...i_tracks. */
362 if (i_track == 0 || i_track > p_vcd->i_tracks) {
363 LOG_ERR ("Invalid track number %d", i_track );
366 p_vcd->in_still = VLC_FALSE;
367 VCDSetOrigin( p_access,
368 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
373 case VCDINFO_ITEM_TYPE_SEGMENT:
375 int i_seg = itemid.num;
377 /* Valid segments go from 0...i_segments-1. */
378 if (itemid.num >= p_vcd->i_segments) {
379 LOG_ERR ( "Invalid segment number: %d", i_seg );
382 vcdinfo_video_segment_type_t segtype =
383 vcdinfo_get_video_type(p_vcd->vcd, i_seg);
385 dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
386 vcdinfo_video_type2str(p_vcd->vcd, i_seg),
387 (int) segtype, itemid.num);
391 case VCDINFO_FILES_VIDEO_NTSC_STILL:
392 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
393 case VCDINFO_FILES_VIDEO_PAL_STILL:
394 case VCDINFO_FILES_VIDEO_PAL_STILL2:
395 p_vcd->in_still = VLC_TRUE;
398 p_vcd->in_still = VLC_FALSE;
400 VCDSetOrigin( p_access, p_vcd->p_segments[i_seg],
407 case VCDINFO_ITEM_TYPE_LID:
408 /* LIDs go from 1..i_lids. */
409 if (itemid.num == 0 || itemid.num > p_vcd->i_lids) {
410 LOG_ERR ( "Invalid LID number: %d", itemid.num );
413 p_vcd->i_lid = itemid.num;
414 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
416 switch (p_vcd->pxd.descriptor_type) {
418 case PSD_TYPE_SELECTION_LIST:
419 case PSD_TYPE_EXT_SELECTION_LIST: {
420 vcdinfo_itemid_t trans_itemid;
421 uint16_t trans_itemid_num;
423 if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
424 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
425 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
426 p_vcd->loop_count = 1;
427 p_vcd->loop_item = trans_itemid;
428 return VCDPlay( p_access, trans_itemid );
432 case PSD_TYPE_PLAY_LIST: {
433 if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
435 return vcdplayer_inc_play_item(p_access)
436 ? VLC_SUCCESS : VLC_EGENERIC;
440 case PSD_TYPE_END_LIST:
441 case PSD_TYPE_COMMAND_LIST:
448 case VCDINFO_ITEM_TYPE_ENTRY:
450 int i_entry = itemid.num;
452 /* Entries go from 0..i_entries-1. */
453 if (itemid.num >= p_vcd->i_entries) {
454 LOG_ERR ("Invalid entry number: %d", i_entry );
457 track_t i_track = vcdinfo_get_track(p_vcd->vcd, i_entry);
458 p_vcd->in_still = VLC_FALSE;
459 VCDSetOrigin( p_access,
460 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
467 LOG_ERR ("unknown entry type" );
471 p_vcd->play_item = itemid;
479 /*****************************************************************************
480 VCDEntryPoints: Reads the information about the entry points on the disc
481 and initializes area information with that.
482 Before calling this track information should have been read in.
483 *****************************************************************************/
485 VCDEntryPoints( access_t * p_access )
487 if (!p_access || !p_access->p_sys) return VLC_FALSE;
490 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
491 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcd->vcd);
492 const track_t i_last_track
493 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcd->vcd))
494 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcd->vcd));
497 if (0 == i_entries) {
498 LOG_ERR ("no entires found -- something is wrong" );
502 p_vcd->p_entries = malloc( sizeof( lsn_t ) * i_entries );
504 if( p_vcd->p_entries == NULL )
506 LOG_ERR ("not enough memory for entry points treatment" );
510 p_vcd->i_entries = i_entries;
512 for( i = 0 ; i < i_entries ; i++ )
514 const track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
515 if( i_track <= i_last_track ) {
516 seekpoint_t *s = vlc_seekpoint_New();
519 snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
521 p_vcd->p_entries[i] = vcdinfo_get_entry_lba(p_vcd->vcd, i);
523 s->psz_name = strdup(psz_entry);
525 (p_vcd->p_entries[i] - vcdinfo_get_track_lba(p_vcd->vcd, i_track))
528 dbg_print( INPUT_DBG_MRL,
529 "%s, lsn %d, byte_offset %ld\n",
530 s->psz_name, p_vcd->p_entries[i],
531 (unsigned long int) s->i_byte_offset);
532 TAB_APPEND( p_vcd->p_title[i_track-1]->i_seekpoint,
533 p_vcd->p_title[i_track-1]->seekpoint, s );
536 msg_Warn( p_access, "wrong track number found in entry points" );
538 p_vcd->b_valid_ep = VLC_TRUE;
543 /*****************************************************************************
544 * VCDSegments: Reads the information about the segments the disc.
545 *****************************************************************************/
547 VCDSegments( access_t * p_access )
549 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
553 p_vcd->i_segments = vcdinfo_get_num_segments(p_vcd->vcd);
555 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
556 "num LIDs=%d", p_vcd->i_segments);
558 if ( 0 == p_vcd->i_segments ) return VLC_FALSE;
560 t = p_vcd->p_title[p_vcd->i_titles] = vlc_input_title_New();
563 t->i_size = 0; /* Not sure Segments have a size associated */
564 t->psz_name = strdup(_("Segments"));
566 /* We have one additional segment allocated so we can get the size
567 by subtracting seg[i+1] - seg[i].
569 p_vcd->p_segments = malloc( sizeof( lsn_t ) * (p_vcd->i_segments+1) );
570 if( p_vcd->p_segments == NULL )
572 LOG_ERR ("not enough memory for segment treatment" );
576 for( i = 0 ; i < p_vcd->i_segments ; i++ )
578 char psz_segment[100];
579 seekpoint_t *s = vlc_seekpoint_New();
580 p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
582 snprintf( psz_segment, sizeof(psz_segment), "%s%02d", _("Segment "),
585 s->i_byte_offset = 0; /* Not sure what this would mean here */
586 s->psz_name = strdup(psz_segment);
587 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
590 p_vcd->p_segments[p_vcd->i_segments] =
591 p_vcd->p_segments[p_vcd->i_segments-1]+
592 vcdinfo_get_seg_sector_count(p_vcd->vcd, p_vcd->i_segments-1);
597 /*****************************************************************************
598 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
600 We start area addressing for tracks at 1 since the default area 0
601 is reserved for segments.
602 *****************************************************************************/
604 VCDTitles( access_t * p_access )
606 /* We'll assume a VCD has its first MPEG track
607 cdio_get_first_track_num()+1 could be used if one wanted to be
608 very careful about this. Note: cdio_get_first_track() will give the
609 ISO-9660 track before the MPEG tracks.
612 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
615 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
619 for( i = 1 ; i <= p_vcd->i_tracks ; i++ )
621 input_title_t *t = p_vcd->p_title[i-1] = vlc_input_title_New();
623 uint32_t i_secsize = vcdinfo_get_track_sect_count( p_vcd->vcd, i );
625 snprintf( psz_track, sizeof(psz_track), "%s%02d", _("Track "),
628 t->i_size = (i_secsize) * (int64_t) M2F2_SECTOR_SIZE;
629 t->psz_name = strdup(psz_track);
631 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld",
641 /*****************************************************************************
642 VCDLIDs: Reads the LIST IDs from the LOT.
643 *****************************************************************************/
645 VCDLIDs( access_t * p_access )
647 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
649 unsigned int i_lid, i_title;
651 p_vcd->i_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
652 p_vcd->i_lid = VCDINFO_INVALID_ENTRY;
654 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
655 "num LIDs=%d", p_vcd->i_lids);
657 if ( 0 == p_vcd->i_lids ) return VLC_FALSE;
659 if (vcdinfo_read_psd (p_vcd->vcd)) {
661 vcdinfo_visit_lot (p_vcd->vcd, VLC_FALSE);
665 We need to change libvcdinfo to be more robust when there are
666 problems reading the extended PSD. Given that area-highlighting and
667 selection features in the extended PSD haven't been implemented,
668 it's best then to not try to read this at all.
670 if (vcdinfo_get_psd_x_size(p_vcd->vcd))
671 vcdinfo_visit_lot (p_vcd->vcd, VLC_TRUE);
675 /* Set up LIDs Navigation Menu */
676 t = vlc_input_title_New();
677 t->b_menu = VLC_TRUE;
678 t->psz_name = strdup( "LIDs" );
680 i_title = p_vcd->i_tracks;
681 for( i_lid = 1 ; i_lid <= p_vcd->i_lids ; i_lid++ )
684 seekpoint_t *s = vlc_seekpoint_New();
686 snprintf( psz_lid, sizeof(psz_lid), "%s%02d", _("LID "),
689 s->i_byte_offset = 0; /* A lid doesn't have an offset
690 size associated with it */
691 s->psz_name = strdup(psz_lid);
692 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
696 #if DYNAMICALLY_ALLOCATED
697 TAB_APPEND( p_vcd->i_titles, p_vcd->p_title, t );
699 p_vcd->p_title[p_vcd->i_titles] = t;
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 vcdplayer_t *p_vcd = (vcdplayer_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 i_lsn, track_t i_track,
831 const vcdinfo_itemid_t *p_itemid )
833 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
835 unsigned int i_title = i_track - 1; /* For now */
837 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
838 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
841 p_vcd->i_lsn = i_lsn;
842 p_vcd->i_track = i_track;
843 p_vcd->track_lsn = vcdinfo_get_track_lsn(p_vcd->vcd, i_track);
845 p_vcd->play_item.num = p_itemid->num;
846 p_vcd->play_item.type = p_itemid->type;
848 vcdplayer_set_origin(p_access);
850 p_access->info.i_pos = ( i_lsn - p_vcd->track_lsn )
852 p_access->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
853 | INPUT_UPDATE_SEEKPOINT;
855 if (p_itemid->type == VCDINFO_ITEM_TYPE_ENTRY) {
856 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
857 "chapter", _("Entry"), "Setting entry/segment");
858 p_access->info.i_title = i_track-1;
859 p_access->info.i_size = p_vcd->p_title[i_title]->i_size;
860 p_access->info.i_seekpoint = p_itemid->num;
861 } else if (p_itemid->type == VCDINFO_ITEM_TYPE_SEGMENT) {
862 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
863 "chapter", _("Segment"), "Setting entry/segment");
864 /* The last title entry is the for segments (when segments exist
865 and they must here. The segment seekpoints are stored after
866 the entry seekpoints and (zeroed) lid seekpoints.
868 p_access->info.i_title = p_vcd->i_titles - 1;
869 p_access->info.i_size = 150 * M2F2_SECTOR_SIZE;
870 p_access->info.i_seekpoint = p_vcd->i_entries
871 + p_vcd->i_lids + p_itemid->num;
875 VCDUpdateTitle( p_access );
879 /*****************************************************************************
880 * vcd_Open: Opens a VCD device or file initializes, a list of
881 tracks, segements and entry lsns and sizes and returns an opaque handle.
882 *****************************************************************************/
883 static vcdinfo_obj_t *
884 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
886 access_t *p_access = (access_t *)p_this;
887 vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
888 vcdinfo_obj_t *p_vcdobj;
892 dbg_print(INPUT_DBG_CALL, "called with %s\n", psz_dev);
894 if( !psz_dev ) return NULL;
896 actual_dev=strdup(psz_dev);
897 if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
905 Save summary info on tracks, segments and entries...
908 if ( 0 < (p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
909 p_vcd->track = (vcdplayer_play_item_info_t *)
910 calloc(p_vcd->i_tracks, sizeof(vcdplayer_play_item_info_t));
912 for (i=0; i<p_vcd->i_tracks; i++) {
913 unsigned int track_num=i+1;
914 p_vcd->track[i].size =
915 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
916 p_vcd->track[i].start_LSN =
917 vcdinfo_get_track_lsn(p_vcdobj, track_num);
922 if ( 0 < (p_vcd->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
923 p_vcd->entry = (vcdplayer_play_item_info_t *)
924 calloc(p_vcd->i_entries, sizeof(vcdplayer_play_item_info_t));
926 for (i=0; i<p_vcd->i_entries; i++) {
927 p_vcd->entry[i].size = vcdinfo_get_entry_sect_count(p_vcdobj, i);
928 p_vcd->entry[i].start_LSN = vcdinfo_get_entry_lba(p_vcdobj, i);
933 if ( 0 < (p_vcd->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
934 p_vcd->segment = (vcdplayer_play_item_info_t *)
935 calloc(p_vcd->i_segments, sizeof(vcdplayer_play_item_info_t));
937 for (i=0; i<p_vcd->i_segments; i++) {
938 p_vcd->segment[i].size = vcdinfo_get_seg_sector_count(p_vcdobj, i);
939 p_vcd->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
942 p_vcd->segment = NULL;
948 /****************************************************************************
949 * VCDReadSector: Read a sector (2324 bytes)
950 ****************************************************************************/
952 VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
953 lsn_t i_lsn, byte_t * p_buffer )
956 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
957 uint8_t data [M2F2_SECTOR_SIZE];
960 vcdsector_t vcd_sector;
962 if( cdio_read_mode2_sector( vcdinfo_get_cd_image( p_vcd ),
963 &vcd_sector, i_lsn, VLC_TRUE )
966 msg_Warn( p_this, "Could not read LSN %lu",
967 (long unsigned int) i_lsn );
971 memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
976 /****************************************************************************
977 Update the "varname" variable to i_num without triggering a callback.
978 ****************************************************************************/
980 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
981 const char *p_varname, char *p_label,
982 const char *p_debug_label)
987 const vcdplayer_t *p_vcd = (vcdplayer_t *)p_vcd_access->p_sys;
988 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
992 text.psz_string = p_label;
993 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
995 var_Change( p_access, p_varname, i_action, &val, NULL );
999 /*****************************************************************************
1001 *****************************************************************************/
1003 /*****************************************************************************
1005 read in meta-information about VCD: the number of tracks, segments,
1006 entries, size and starting information. Then set up state variables so
1007 that we read/seek starting at the location specified.
1009 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
1010 and VLC_EGENERIC for some other error.
1011 *****************************************************************************/
1013 E_(VCDOpen) ( vlc_object_t *p_this )
1015 access_t *p_access = (access_t *)p_this;
1018 vcdinfo_itemid_t itemid;
1019 vlc_bool_t b_play_ok;
1020 vlc_bool_t play_single_item = VLC_FALSE;
1022 p_access->pf_read = NULL;
1023 p_access->pf_block = VCDReadBlock;
1024 p_access->pf_control = VCDControl;
1025 p_access->pf_seek = VCDSeek;
1027 p_access->info.i_update = 0;
1028 p_access->info.i_size = 0;
1029 p_access->info.i_pos = 0;
1030 p_access->info.b_eof = VLC_FALSE;
1031 p_access->info.i_title = 0;
1032 p_access->info.i_seekpoint = 0;
1034 p_vcd = malloc( sizeof(vcdplayer_t) );
1038 LOG_ERR ("out of memory" );
1042 p_access->p_sys = (access_sys_t *) p_vcd;
1044 /* Set where to log errors messages from libcdio. */
1045 p_vcd_access = p_access;
1046 cdio_log_set_handler ( cdio_log_handler );
1047 vcd_log_set_handler ( vcd_log_handler );
1049 psz_source = VCDParse( p_access, &itemid, &play_single_item );
1051 if ( NULL == psz_source )
1054 return( VLC_EGENERIC );
1057 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
1058 psz_source, p_access->psz_path );
1060 p_vcd->psz_source = strdup(psz_source);
1061 p_vcd->i_debug = config_GetInt( p_this,
1062 MODULE_STRING "-debug" );
1063 p_vcd->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
1064 "-blocks-per-read" );
1065 p_vcd->in_still = VLC_FALSE;
1066 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
1067 p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT,
1069 p_vcd->p_meta = vlc_meta_New();
1070 p_vcd->p_segments = NULL;
1071 p_vcd->p_entries = NULL;
1075 if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
1077 msg_Warn( p_access, "could not open %s", psz_source );
1081 p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
1083 /* Get track information. */
1084 p_vcd->i_tracks = vcdinfo_get_num_tracks(p_vcd->vcd);
1086 if( p_vcd->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcd->i_tracks ) {
1087 vcdinfo_close( p_vcd->vcd );
1088 LOG_ERR ("no movie tracks found" );
1092 /* Build Navigation Title table for the tracks. */
1093 VCDTitles( p_access );
1095 /* Add into the above entry points as "Chapters". */
1096 if( ! VCDEntryPoints( p_access ) )
1098 msg_Warn( p_access, "could not read entry points, will not use them" );
1099 p_vcd->b_valid_ep = VLC_FALSE;
1102 /* Initialize LID info and add that as a menu item */
1103 if( ! VCDLIDs( p_access ) )
1105 msg_Warn( p_access, "could not read entry LIDs" );
1108 /* Initialize segment information and add that a "Track". */
1109 VCDSegments( p_access );
1111 b_play_ok = (VLC_SUCCESS == VCDPlay( p_access, itemid ));
1113 if ( ! b_play_ok ) {
1114 vcdinfo_close( p_vcd->vcd );
1118 p_access->psz_demux = strdup( "ps" );
1121 p_vcd->p_intf = intf_Create( p_access, "vcdx" );
1122 p_vcd->p_intf->b_block = VLC_FALSE;
1123 intf_RunThread( p_vcd->p_intf );
1127 if (play_single_item)
1128 VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
1139 return VLC_EGENERIC;
1142 /*****************************************************************************
1143 * VCDClose: closes VCD releasing allocated memory.
1144 *****************************************************************************/
1146 E_(VCDClose) ( vlc_object_t *p_this )
1148 access_t *p_access = (access_t *)p_this;
1149 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
1151 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
1153 vcdinfo_close( p_vcd->vcd );
1155 FREE_AND_NULL( p_vcd->p_entries );
1156 FREE_AND_NULL( p_vcd->p_segments );
1157 FREE_AND_NULL( p_vcd->psz_source );
1158 FREE_AND_NULL( p_vcd->track );
1159 FREE_AND_NULL( p_vcd->segment );
1160 FREE_AND_NULL( p_vcd->entry );
1163 p_access->p_sys = NULL;
1164 p_vcd_access = NULL;
1167 /*****************************************************************************
1168 * Control: The front-end or vlc engine calls here to ether get
1169 * information such as meta information or plugin capabilities or to
1170 * issue miscellaneous "set" requests.
1171 *****************************************************************************/
1172 static int VCDControl( access_t *p_access, int i_query, va_list args )
1174 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
1178 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1179 "query %d", i_query );
1183 /* Pass back a copy of meta information that was gathered when we
1184 during the Open/Initialize call.
1186 case ACCESS_GET_META:
1188 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
1190 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1192 if ( p_vcd->p_meta ) {
1193 *pp_meta = vlc_meta_Duplicate( p_vcd->p_meta );
1194 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1196 msg_Warn( p_access, "tried to copy NULL meta info" );
1200 return VLC_EGENERIC;
1202 case ACCESS_CAN_SEEK:
1203 case ACCESS_CAN_FASTSEEK:
1204 case ACCESS_CAN_PAUSE:
1205 case ACCESS_CAN_CONTROL_PACE:
1207 vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
1209 dbg_print( INPUT_DBG_EVENT,
1210 "seek/fastseek/pause/can_control_pace" );
1211 *pb_bool = VLC_TRUE;
1217 case ACCESS_GET_MTU:
1218 pi_int = (int*)va_arg( args, int * );
1219 *pi_int = (p_vcd->i_blocks_per_read * M2F2_SECTOR_SIZE);
1220 dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
1223 case ACCESS_GET_PTS_DELAY:
1225 int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
1226 *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
1227 * MILLISECONDS_PER_SEC;
1228 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1234 case ACCESS_SET_PAUSE_STATE:
1235 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1239 case ACCESS_GET_TITLE_INFO:
1241 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1242 + strlen(p_vcd->psz_source) + sizeof("@E999")+3;
1243 input_title_t ***ppp_title
1244 = (input_title_t***)va_arg( args, input_title_t*** );
1245 char *psz_mrl = malloc( psz_mrl_max );
1248 pi_int = (int*)va_arg( args, int* );
1250 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1253 if( psz_mrl == NULL ) {
1254 msg_Warn( p_access, "out of memory" );
1256 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1257 VCD_MRL_PREFIX, p_vcd->psz_source);
1258 VCDMetaInfo( p_access, psz_mrl );
1262 /* Duplicate title info */
1263 if( p_vcd->i_titles == 0 )
1265 *pi_int = 0; ppp_title = NULL;
1268 *pi_int = p_vcd->i_titles;
1269 *ppp_title = malloc(sizeof( input_title_t **) * p_vcd->i_titles );
1271 if (!*ppp_title) return VLC_ENOMEM;
1273 for( i = 0; i < p_vcd->i_titles; i++ )
1275 if ( p_vcd->p_title[i] )
1277 vlc_input_title_Duplicate( p_vcd->p_title[i] );
1282 case ACCESS_SET_TITLE:
1283 i = (int)va_arg( args, int );
1285 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1286 if( i != p_access->info.i_title )
1288 vcdinfo_itemid_t itemid;
1289 track_t i_track = i+1;
1290 unsigned int i_entry =
1291 vcdinfo_track_get_entry( p_vcd->vcd, i_track);
1293 /* FIXME! For now we are assuming titles are only
1294 tracks and that track == title+1 */
1295 itemid.num = i_track;
1296 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1298 VCDSetOrigin(p_access,
1299 vcdinfo_get_entry_lba(p_vcd->vcd, i_entry),
1304 case ACCESS_SET_SEEKPOINT:
1306 input_title_t *t = p_vcd->p_title[p_access->info.i_title];
1307 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1309 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1310 if( t->i_seekpoint > 0 )
1312 track_t i_track = p_access->info.i_title+1;
1315 /* FIXME! For now we are assuming titles are only
1316 tracks and that track == title+1 and we the play
1317 item is entries (not tracks or lids).
1318 We need to generalize all of this.
1321 if (i < p_vcd->i_entries)
1323 p_vcd->play_item.num = i;
1324 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1325 lsn = vcdinfo_get_entry_lba(p_vcd->vcd, i);
1326 } else if ( i < p_vcd->i_entries + p_vcd->i_lids )
1328 p_vcd->play_item.num = i = i - p_vcd->i_entries;
1329 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_LID;
1333 p_vcd->play_item.num = i = i - p_vcd->i_entries
1335 p_vcd->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1336 lsn = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
1339 VCDSetOrigin( p_access,
1340 vcdinfo_get_entry_lba(p_vcd->vcd, i),
1341 i_track, &(p_vcd->play_item) );
1346 case ACCESS_SET_PRIVATE_ID_STATE:
1347 dbg_print( INPUT_DBG_EVENT, "set private id" );
1348 return VLC_EGENERIC;
1351 msg_Warn( p_access, "unimplemented query in control" );
1352 return VLC_EGENERIC;