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, 2005 the VideoLAN team
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 along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_interface.h>
38 #include <vlc_input.h>
39 #include <vlc_access.h>
40 #include <vlc_charset.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>
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 bool VCDEntryPoints ( access_t * );
64 static bool VCDLIDs ( access_t * );
65 static bool VCDSegments ( access_t * );
66 static int VCDTitles ( access_t * );
67 static char *VCDParse ( access_t *,
68 /*out*/ vcdinfo_itemid_t * p_itemid ,
69 /*out*/ bool *play_single_item );
71 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
72 const char *p_varname, char *p_label,
73 const char *p_debug_label );
75 static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
77 /****************************************************************************
79 ****************************************************************************/
81 /* FIXME: This variable is a hack. Would be nice to eliminate the
84 static access_t *p_vcd_access = NULL;
86 /* process messages that originate from libcdio. */
88 cdio_log_handler (cdio_log_level_t level, const char message[])
90 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
94 if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
95 msg_Dbg( p_vcd_access, "%s", message);
98 msg_Warn( p_vcd_access, "%s", message);
101 case CDIO_LOG_ASSERT:
102 msg_Err( p_vcd_access, "%s", message);
105 msg_Warn( p_vcd_access, "%s\n%s %d", message,
106 "The above message had unknown log level", level);
111 /* process messages that originate from vcdinfo. */
113 vcd_log_handler (vcd_log_level_t level, const char message[])
115 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
119 if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
120 msg_Dbg( p_vcd_access, "%s", message);
123 msg_Warn( p_vcd_access, "%s", message);
127 msg_Err( p_vcd_access, "%s", message);
130 msg_Warn( p_vcd_access, "%s\n%s %d", message,
131 "The above message had unknown vcdimager log level", level);
136 /*****************************************************************************
137 VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
138 NULL is returned if something went wrong.
139 *****************************************************************************/
141 VCDReadBlock( access_t * p_access )
143 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
144 const int i_blocks = p_vcdplayer->i_blocks_per_read;
149 dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
150 (long unsigned int) p_vcdplayer->i_lsn );
152 /* Allocate a block for the reading */
153 if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
155 msg_Err( p_access, "cannot get a new block of size: %i",
156 i_blocks * M2F2_SECTOR_SIZE );
157 block_Release( p_block );
161 p_buf = (uint8_t *) p_block->p_buffer;
162 for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
164 vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
166 p_access->info.i_pos += M2F2_SECTOR_SIZE;
168 switch ( read_status ) {
170 /* End reached. Return NULL to indicated this. */
171 /* We also set the postion to the end so the higher level
172 (demux?) doesn't try to keep reading. If everything works out
173 right this shouldn't have to happen.
176 if( p_access->info.i_pos != p_access->info.i_size ) {
178 "At end but pos (%llu) is not size (%llu). Adjusting.",
179 p_access->info.i_pos, p_access->info.i_size );
180 p_access->info.i_pos = p_access->info.i_size;
184 block_Release( p_block );
188 /* Some sort of error. Should we increment lsn? to skip block? */
189 block_Release( p_block );
191 case READ_STILL_FRAME:
192 /* FIXME The below should be done in an event thread.
196 msleep( MILLISECONDS_PER_SEC * *p_buf );
197 VCDSetOrigin(p_access, p_vcdplayer->origin_lsn,
198 p_vcdplayer->i_track, &(p_vcdplayer->play_item));
199 // p_vcd->in_still = false;
200 dbg_print(INPUT_DBG_STILL, "still wait time done");
202 vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);
205 block_Release( p_block );
214 p_buf += M2F2_SECTOR_SIZE;
215 /* Update seekpoint */
216 if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
218 size_t i_entry = p_vcdplayer->play_item.num+1;
219 lsn_t i_lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
220 if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
222 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
223 "entry change to %zu, current LSN %u >= end %u",
224 i_entry, p_vcdplayer->i_lsn, i_lsn);
226 p_vcdplayer->play_item.num = i_entry;
228 VCDSetOrigin( p_access, i_lsn, p_vcdplayer->i_track,
229 &(p_vcdplayer->play_item) );
238 /****************************************************************************
240 ****************************************************************************/
242 VCDSeek( access_t * p_access, int64_t i_pos )
244 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
246 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
247 const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
248 unsigned int i_entry = VCDINFO_INVALID_ENTRY;
251 /* Next sector to read */
252 p_access->info.i_pos = i_pos;
253 p_vcdplayer->i_lsn = (i_pos / (int64_t) M2F2_SECTOR_SIZE) +
254 p_vcdplayer->origin_lsn;
256 switch (p_vcdplayer->play_item.type)
258 case VCDINFO_ITEM_TYPE_TRACK:
259 case VCDINFO_ITEM_TYPE_ENTRY:
262 p_vcdplayer->b_valid_ep = false;
267 if( p_vcdplayer->b_valid_ep )
269 for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
271 if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
273 VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
274 "chapter", _("Entry"), "Setting entry" );
280 vcdinfo_itemid_t itemid;
281 itemid.num = i_entry;
282 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
283 VCDSetOrigin(p_access, p_vcdplayer->i_lsn,
284 p_vcdplayer->i_track, &itemid);
288 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
289 "orig %lu, cur: %lu, offset: %lld, entry %d",
290 (long unsigned int) p_vcdplayer->origin_lsn,
291 (long unsigned int) p_vcdplayer->i_lsn, i_pos,
295 for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
297 if( i_seekpoint + 1 >= t->i_seekpoint ) break;
298 if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
301 /* Update current seekpoint */
302 if( i_seekpoint != p_access->info.i_seekpoint )
304 dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
305 (long unsigned int) i_seekpoint );
306 p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
307 p_access->info.i_seekpoint = i_seekpoint;
310 p_access->info.b_eof = false;
314 /*****************************************************************************
315 VCDEntryPoints: Reads the information about the entry points on the disc
316 and initializes area information with that.
317 Before calling this track information should have been read in.
318 *****************************************************************************/
320 VCDEntryPoints( access_t * p_access )
322 if (!p_access || !p_access->p_sys) return false;
324 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
325 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdplayer->vcd);
326 const track_t i_last_track
327 = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
328 + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
331 if (0 == i_entries) {
332 LOG_ERR ("no entires found -- something is wrong" );
336 p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries );
338 if( p_vcdplayer->p_entries == NULL )
340 LOG_ERR ("not enough memory for entry points treatment" );
344 p_vcdplayer->i_entries = i_entries;
346 for( i = 0 ; i < i_entries ; i++ )
348 const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
349 if( i_track <= i_last_track )
351 seekpoint_t *s = vlc_seekpoint_New();
354 snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i );
356 p_vcdplayer->p_entries[i] =
357 vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
359 s->psz_name = strdup(psz_entry);
360 s->i_byte_offset = (p_vcdplayer->p_entries[i]
361 - vcdinfo_get_track_lsn(p_vcdplayer->vcd,i_track))
364 dbg_print( INPUT_DBG_MRL, "%s, lsn %d, byte_offset %ld",
365 s->psz_name, p_vcdplayer->p_entries[i],
366 (unsigned long int) s->i_byte_offset);
367 TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
368 p_vcdplayer->p_title[i_track-1]->seekpoint, s );
371 msg_Warn( p_access, "wrong track number found in entry points" );
373 p_vcdplayer->b_valid_ep = true;
377 /*****************************************************************************
378 * VCDSegments: Reads the information about the segments the disc.
379 *****************************************************************************/
381 VCDSegments( access_t * p_access )
383 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
387 p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
389 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
390 "Segments: %d", p_vcdplayer->i_segments);
392 if ( 0 == p_vcdplayer->i_segments ) return false;
394 t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
395 p_vcdplayer->i_titles++;
397 t->i_size = 0; /* Not sure Segments have a size associated */
398 t->psz_name = strdup(_("Segments"));
400 /* We have one additional segment allocated so we can get the size
401 by subtracting seg[i+1] - seg[i].
403 p_vcdplayer->p_segments=malloc(sizeof(lsn_t)*(p_vcdplayer->i_segments+1));
404 if( p_vcdplayer->p_segments == NULL )
406 LOG_ERR ("not enough memory for segment treatment" );
410 for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
412 char psz_segment[100];
413 seekpoint_t *s = vlc_seekpoint_New();
414 p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
416 snprintf( psz_segment, sizeof(psz_segment), "%s %02d", _("Segment"),
419 s->i_byte_offset = 0; /* Not sure what this would mean here */
420 s->psz_name = strdup(psz_segment);
421 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
424 p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
425 p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
426 vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
427 p_vcdplayer->i_segments-1);
432 /*****************************************************************************
433 Build title table which will be returned via ACCESS_GET_TITLE_INFO.
435 We start area addressing for tracks at 1 since the default area 0
436 is reserved for segments.
437 *****************************************************************************/
439 VCDTitles( access_t * p_access )
441 /* We'll assume a VCD has its first MPEG track
442 cdio_get_first_track_num()+1 could be used if one wanted to be
443 very careful about this. Note: cdio_get_first_track() will give the
444 ISO-9660 track before the MPEG tracks.
447 if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
450 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
453 p_vcdplayer->i_titles = 0;
454 for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
456 input_title_t *t = p_vcdplayer->p_title[i-1] =
457 vlc_input_title_New();
460 snprintf( psz_track, sizeof(psz_track), "%s %02d", _("Track"), i );
461 t->i_size = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
462 i ) * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
463 t->psz_name = strdup(psz_track);
465 dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld", i, t->i_size );
467 p_vcdplayer->i_titles++;
474 /*****************************************************************************
475 VCDLIDs: Reads the LIST IDs from the LOT.
476 *****************************************************************************/
478 VCDLIDs( access_t * p_access )
480 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
482 unsigned int i_lid, i_title;
484 p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
485 p_vcdplayer->i_lid = VCDINFO_INVALID_ENTRY;
487 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
488 "LIDs: %d", p_vcdplayer->i_lids);
490 if ( 0 == p_vcdplayer->i_lids ) return false;
492 if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
494 vcdinfo_visit_lot (p_vcdplayer->vcd, false);
498 We need to change libvcdinfo to be more robust when there are
499 problems reading the extended PSD. Given that area-highlighting and
500 selection features in the extended PSD haven't been implemented,
501 it's best then to not try to read this at all.
503 if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
504 vcdinfo_visit_lot (p_vcdplayer->vcd, true);
508 /* Set up LIDs Navigation Menu */
509 t = vlc_input_title_New();
511 t->psz_name = strdup( "LIDs" );
513 i_title = p_vcdplayer->i_tracks;
514 for( i_lid = 1 ; i_lid <= p_vcdplayer->i_lids ; i_lid++ )
517 seekpoint_t *s = vlc_seekpoint_New();
519 snprintf( psz_lid, sizeof(psz_lid), "%s %02d", _("LID"), i_lid );
521 s->i_byte_offset = 0; /* A lid doesn't have an offset
522 size associated with it */
523 s->psz_name = strdup(psz_lid);
524 TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
527 #ifdef DYNAMICALLY_ALLOCATED
528 TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
530 p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
531 p_vcdplayer->i_titles++;
537 /*****************************************************************************
538 * VCDParse: parse command line
539 *****************************************************************************/
541 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
542 /*out*/ bool *play_single_item )
544 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
549 if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
550 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
552 *play_single_item = false;
556 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
561 /* On Win32 we want the VCD access plugin to be explicitly requested,
562 * we end up with lots of problems otherwise */
563 if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
566 if( !p_access->psz_path )
571 psz_parser = psz_source = strdup( p_access->psz_path );
573 /* Parse input string :
574 * [device][@[type][title]] */
575 while( *psz_parser && *psz_parser != '@' )
580 if( *psz_parser == '@' )
582 /* Found the divide between the source name and the
583 type+entry number. */
589 switch(*psz_parser) {
591 p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
593 *play_single_item = true;
596 p_itemid->type = VCDINFO_ITEM_TYPE_LID;
598 *play_single_item = false;
601 p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
603 *play_single_item = true;
606 p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
608 *play_single_item = true;
614 num = strtol( psz_parser, &psz_next, 10 );
615 if ( *psz_parser != '\0' && *psz_next == '\0')
621 *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
628 /* No source specified, so figure it out. */
629 if( !p_access->psz_access ) return NULL;
631 psz_source = config_GetPsz( p_access, "vcd" );
633 if( !psz_source || 0==strlen(psz_source) )
636 /* Scan for a CD-ROM drive with a VCD in it. */
637 char **cd_drives = cdio_get_devices_with_cap(NULL,
638 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
639 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
641 if( NULL == cd_drives ) return NULL;
642 if( cd_drives[0] == NULL )
644 cdio_free_device_list( cd_drives );
647 psz_source = strdup( cd_drives[0] );
648 cdio_free_device_list( cd_drives );
652 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
653 "source=%s entry=%d type=%d",
654 psz_source, p_itemid->num, p_itemid->type);
660 Sets start origin for subsequent seeks/reads
663 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
664 const vcdinfo_itemid_t *p_itemid )
666 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
668 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
669 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn, i_track );
671 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
673 switch (p_vcdplayer->play_item.type)
675 case VCDINFO_ITEM_TYPE_ENTRY:
676 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
677 "chapter", _("Entry"), "Setting entry/segment");
678 p_access->info.i_title = i_track-1;
679 if (p_vcdplayer->b_track_length)
681 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
682 p_access->info.i_pos = (int64_t) M2F2_SECTOR_SIZE *
683 (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track)-i_lsn);
685 p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
686 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd,p_itemid->num);
687 p_access->info.i_pos = 0;
689 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %llu, pos: %llu",
690 p_access->info.i_size, p_access->info.i_pos );
691 p_access->info.i_seekpoint = p_itemid->num;
694 case VCDINFO_ITEM_TYPE_SEGMENT:
695 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
696 "chapter", _("Segment"), "Setting entry/segment");
697 /* The last title entry is the for segments (when segments exist
698 and they must here. The segment seekpoints are stored after
699 the entry seekpoints and (zeroed) lid seekpoints.
701 p_access->info.i_title = p_vcdplayer->i_titles - 1;
702 p_access->info.i_size = 0; /* No seeking on stills, please. */
703 p_access->info.i_pos = 0;
704 p_access->info.i_seekpoint = p_vcdplayer->i_entries
705 + p_vcdplayer->i_lids + p_itemid->num;
708 case VCDINFO_ITEM_TYPE_TRACK:
709 p_access->info.i_title = i_track-1;
710 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
711 p_access->info.i_pos = 0;
712 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
717 msg_Warn( p_access, "can't set origin for play type %d",
718 p_vcdplayer->play_item.type );
721 p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
722 |INPUT_UPDATE_SEEKPOINT;
724 VCDUpdateTitle( p_access );
728 /*****************************************************************************
729 * vcd_Open: Opens a VCD device or file initializes, a list of
730 tracks, segements and entry lsns and sizes and returns an opaque handle.
731 *****************************************************************************/
732 static vcdinfo_obj_t *
733 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
735 access_t *p_access = (access_t *)p_this;
736 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
737 vcdinfo_obj_t *p_vcdobj;
741 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
743 if( !psz_dev ) return NULL;
745 actual_dev= ToLocaleDup(psz_dev);
746 if( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
755 Save summary info on tracks, segments and entries...
758 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) )
760 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
761 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
763 for (i=0; i<p_vcdplayer->i_tracks; i++)
765 unsigned int track_num=i+1;
766 p_vcdplayer->track[i].size =
767 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
768 p_vcdplayer->track[i].start_LSN =
769 vcdinfo_get_track_lsn(p_vcdobj, track_num);
772 p_vcdplayer->track = NULL;
774 if( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) )
776 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
777 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
779 for (i=0; i<p_vcdplayer->i_entries; i++)
781 p_vcdplayer->entry[i].size =
782 vcdinfo_get_entry_sect_count(p_vcdobj, i);
783 p_vcdplayer->entry[i].start_LSN =
784 vcdinfo_get_entry_lsn(p_vcdobj, i);
787 p_vcdplayer->entry = NULL;
789 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) )
791 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
792 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
794 for (i=0; i<p_vcdplayer->i_segments; i++)
796 p_vcdplayer->segment[i].size =
797 vcdinfo_get_seg_sector_count(p_vcdobj, i);
798 p_vcdplayer->segment[i].start_LSN =
799 vcdinfo_get_seg_lsn(p_vcdobj, i);
802 p_vcdplayer->segment = NULL;
807 /****************************************************************************
808 Update the "varname" variable to i_num without triggering a callback.
809 ****************************************************************************/
811 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
812 const char *p_varname, char *p_label,
813 const char *p_debug_label)
819 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
820 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
825 text.psz_string = p_label;
826 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
828 var_Change( p_access, p_varname, i_action, &val, NULL );
832 /*****************************************************************************
834 *****************************************************************************/
836 /*****************************************************************************
838 read in meta-information about VCD: the number of tracks, segments,
839 entries, size and starting information. Then set up state variables so
840 that we read/seek starting at the location specified.
842 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
843 and VLC_EGENERIC for some other error.
844 *****************************************************************************/
846 VCDOpen ( vlc_object_t *p_this )
848 access_t *p_access = (access_t *)p_this;
849 vcdplayer_t *p_vcdplayer;
851 vcdinfo_itemid_t itemid;
852 bool play_single_item = false;
854 p_access->pf_read = NULL;
855 p_access->pf_block = VCDReadBlock;
856 p_access->pf_control = VCDControl;
857 p_access->pf_seek = VCDSeek;
859 p_access->info.i_update = 0;
860 p_access->info.i_size = 0;
861 p_access->info.i_pos = 0;
862 p_access->info.b_eof = false;
863 p_access->info.i_title = 0;
864 p_access->info.i_seekpoint = 0;
866 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
868 if( p_vcdplayer == NULL )
871 p_vcdplayer->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
872 p_access->p_sys = (access_sys_t *) p_vcdplayer;
874 /* Set where to log errors messages from libcdio. */
875 p_vcd_access = p_access;
876 cdio_log_set_handler ( cdio_log_handler );
877 vcd_log_set_handler ( vcd_log_handler );
879 psz_source = VCDParse( p_access, &itemid, &play_single_item );
881 if ( NULL == psz_source )
884 return( VLC_EGENERIC );
887 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
888 psz_source, p_access->psz_path );
890 p_vcdplayer->psz_source = strdup(psz_source);
891 p_vcdplayer->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
892 "-blocks-per-read" );
893 p_vcdplayer->b_track_length = config_GetInt( p_this, MODULE_STRING
895 p_vcdplayer->in_still = false;
896 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
897 p_vcdplayer->p_input = access_GetParentInput( p_access );
898 // p_vcdplayer->p_meta = vlc_meta_New();
899 p_vcdplayer->p_segments = NULL;
900 p_vcdplayer->p_entries = NULL;
904 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
909 p_vcdplayer->b_svd = vcdinfo_get_tracksSVD(p_vcdplayer->vcd);
911 /* Get track information. */
912 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
914 if( p_vcdplayer->i_tracks<1 || CDIO_INVALID_TRACK==p_vcdplayer->i_tracks )
916 vcdinfo_close( p_vcdplayer->vcd );
917 LOG_ERR ("no movie tracks found" );
921 /* Build Navigation Title table for the tracks. */
922 VCDTitles( p_access );
924 /* Add into the above entry points as "Chapters". */
925 if( ! VCDEntryPoints( p_access ) )
927 msg_Warn( p_access, "could not read entry points, will not use them" );
928 p_vcdplayer->b_valid_ep = false;
931 /* Initialize LID info and add that as a menu item */
932 if( ! VCDLIDs( p_access ) )
934 msg_Warn( p_access, "could not read entry LIDs" );
937 /* Do we set PBC (via LID) on? */
939 ( VCDINFO_ITEM_TYPE_LID == itemid.type
940 && p_vcdplayer->i_lids > itemid.num )
942 : VCDINFO_INVALID_ENTRY;
944 /* Initialize segment information and add that a "Track". */
945 VCDSegments( p_access );
947 vcdplayer_play( p_access, itemid );
949 free( p_access->psz_demux );
950 p_access->psz_demux = strdup( "ps" );
953 if( play_single_item )
954 VCDFixupPlayList(p_access,p_vcd,psz_source,&itemid,play_single_item);
958 p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
959 p_vcdplayer->p_intf->b_block = false;
961 p_vcdplayer->p_access = p_access;
967 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
969 free( p_vcdplayer->psz_source );
974 /*****************************************************************************
975 * VCDClose: closes VCD releasing allocated memory.
976 *****************************************************************************/
978 VCDClose ( vlc_object_t *p_this )
980 access_t *p_access = (access_t *)p_this;
981 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
983 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
987 for (i=0 ; i<p_vcdplayer->i_titles; i++)
988 if (p_vcdplayer->p_title[i])
989 free(p_vcdplayer->p_title[i]->psz_name);
992 vcdinfo_close( p_vcdplayer->vcd );
994 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
996 FREENULL( p_vcdplayer->p_entries );
997 FREENULL( p_vcdplayer->p_segments );
998 FREENULL( p_vcdplayer->psz_source );
999 FREENULL( p_vcdplayer->track );
1000 FREENULL( p_vcdplayer->segment );
1001 FREENULL( p_vcdplayer->entry );
1002 FREENULL( p_access->psz_demux );
1003 FREENULL( p_vcdplayer );
1004 p_vcd_access = NULL;
1007 /*****************************************************************************
1008 * Control: The front-end or vlc engine calls here to ether get
1009 * information such as meta information or plugin capabilities or to
1010 * issue miscellaneous "set" requests.
1011 *****************************************************************************/
1012 static int VCDControl( access_t *p_access, int i_query, va_list args )
1014 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1018 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1019 "query %d", i_query );
1023 /* Pass back a copy of meta information that was gathered when we
1024 during the Open/Initialize call.
1026 case ACCESS_GET_META:
1027 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1029 if( p_vcdplayer->p_meta )
1031 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg(args,vlc_meta_t**);
1033 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1034 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1038 msg_Warn( p_access, "tried to copy NULL meta info" );
1042 case ACCESS_CAN_SEEK:
1043 case ACCESS_CAN_FASTSEEK:
1044 case ACCESS_CAN_PAUSE:
1045 case ACCESS_CAN_CONTROL_PACE:
1047 dbg_print( INPUT_DBG_EVENT,
1048 "seek/fastseek/pause/can_control_pace" );
1049 *((bool*)va_arg( args, bool* )) = true;
1053 case ACCESS_GET_PTS_DELAY:
1054 *(int64_t*)va_arg(args,int64_t *) = MILLISECONDS_PER_SEC *
1055 var_GetInteger( p_access, MODULE_STRING "-caching" );
1056 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1060 case ACCESS_SET_PAUSE_STATE:
1061 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1064 case ACCESS_GET_TITLE_INFO:
1066 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1067 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1068 input_title_t ***ppp_title
1069 = (input_title_t***)va_arg( args, input_title_t*** );
1070 char *psz_mrl = malloc( psz_mrl_max );
1073 pi_int = (int*)va_arg( args, int* );
1075 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1076 p_vcdplayer->i_titles );
1080 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1081 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1082 VCDMetaInfo( p_access, psz_mrl );
1086 /* Duplicate title info */
1087 if( p_vcdplayer->i_titles == 0 )
1089 *pi_int = 0; ppp_title = NULL;
1092 *pi_int = p_vcdplayer->i_titles;
1093 *ppp_title = malloc(sizeof(input_title_t **)*p_vcdplayer->i_titles);
1095 if (!*ppp_title) return VLC_ENOMEM;
1097 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1098 if( p_vcdplayer->p_title[i] )
1100 vlc_input_title_Duplicate(p_vcdplayer->p_title[i]);
1104 case ACCESS_SET_TITLE:
1105 i = (int)va_arg( args, int );
1107 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1108 if( i != p_access->info.i_title )
1110 vcdinfo_itemid_t itemid;
1111 track_t i_track = i+1;
1112 unsigned int i_entry =
1113 vcdinfo_track_get_entry(p_vcdplayer->vcd,i_track);
1115 if( i < p_vcdplayer->i_tracks )
1117 /* FIXME! For now we are assuming titles are only
1118 tracks and that track == title+1 */
1119 itemid.num = i_track;
1120 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1124 /* FIXME! i_tracks+2 are Segments, but we need to be able
1125 to figure out which segment of that. i_tracks+1 is
1126 either Segments (if no LIDs) or LIDs otherwise. Again
1127 need a way to get the LID number. */
1129 msg_Warn(p_access,"Trying to set track (%u) beyond end "
1130 "of last track (%u).",i+1,p_vcdplayer->i_tracks);
1131 return VLC_EGENERIC;
1134 VCDSetOrigin(p_access,
1135 vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i_entry),
1140 case ACCESS_SET_SEEKPOINT:
1142 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1143 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1145 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1146 if( t->i_seekpoint > 0 )
1148 track_t i_track = p_access->info.i_title+1;
1151 /* FIXME! For now we are assuming titles are only tracks and
1152 that track == title+1 and we the play item is entries (not
1153 tracks or lids). We need to generalize all of this.
1156 if (i < p_vcdplayer->i_entries)
1158 p_vcdplayer->play_item.num = i;
1159 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1160 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1161 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1163 p_vcdplayer->play_item.num = i = i - p_vcdplayer->i_entries;
1164 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1168 p_vcdplayer->play_item.num = i
1169 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1170 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1171 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1174 VCDSetOrigin(p_access,vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i),
1175 i_track,&(p_vcdplayer->play_item));
1180 case ACCESS_SET_PRIVATE_ID_STATE:
1181 dbg_print( INPUT_DBG_EVENT, "set private id" );
1182 return VLC_EGENERIC;
1185 msg_Warn( p_access, "unimplemented query in control" );
1186 return VLC_EGENERIC;