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( INT64_C(1000) * *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, uint64_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 / (uint64_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: %"PRIi64", 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: %"PRIi64, 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( var_InheritBool( 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_location )
571 psz_parser = psz_source = strdup( p_access->psz_location );
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 = var_InheritString( p_access, "vcd" );
635 /* Scan for a CD-ROM drive with a VCD in it. */
636 char **cd_drives = cdio_get_devices_with_cap(NULL,
637 (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
638 |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
640 if( NULL == cd_drives ) return NULL;
641 if( cd_drives[0] == NULL )
643 cdio_free_device_list( cd_drives );
646 psz_source = strdup( cd_drives[0] );
647 cdio_free_device_list( cd_drives );
651 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
652 "source=%s entry=%d type=%d",
653 psz_source, p_itemid->num, p_itemid->type);
659 Sets start origin for subsequent seeks/reads
662 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
663 const vcdinfo_itemid_t *p_itemid )
665 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
667 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
668 "i_lsn: %lu, track: %d", (long unsigned int) i_lsn, i_track );
670 vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
672 switch (p_vcdplayer->play_item.type)
674 case VCDINFO_ITEM_TYPE_ENTRY:
675 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
676 "chapter", _("Entry"), "Setting entry/segment");
677 p_access->info.i_title = i_track-1;
678 if (p_vcdplayer->b_track_length)
680 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
681 p_access->info.i_pos = (uint64_t) M2F2_SECTOR_SIZE *
682 (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track)-i_lsn);
684 p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
685 vcdinfo_get_entry_sect_count(p_vcdplayer->vcd,p_itemid->num);
686 p_access->info.i_pos = 0;
688 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %"PRIu64", pos: %"PRIu64,
689 p_access->info.i_size, p_access->info.i_pos );
690 p_access->info.i_seekpoint = p_itemid->num;
693 case VCDINFO_ITEM_TYPE_SEGMENT:
694 VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
695 "chapter", _("Segment"), "Setting entry/segment");
696 /* The last title entry is the for segments (when segments exist
697 and they must here. The segment seekpoints are stored after
698 the entry seekpoints and (zeroed) lid seekpoints.
700 p_access->info.i_title = p_vcdplayer->i_titles - 1;
701 p_access->info.i_size = 0; /* No seeking on stills, please. */
702 p_access->info.i_pos = 0;
703 p_access->info.i_seekpoint = p_vcdplayer->i_entries
704 + p_vcdplayer->i_lids + p_itemid->num;
707 case VCDINFO_ITEM_TYPE_TRACK:
708 p_access->info.i_title = i_track-1;
709 p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
710 p_access->info.i_pos = 0;
711 p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
716 msg_Warn( p_access, "can't set origin for play type %d",
717 p_vcdplayer->play_item.type );
720 p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
721 |INPUT_UPDATE_SEEKPOINT;
723 VCDUpdateTitle( p_access );
727 /*****************************************************************************
728 * vcd_Open: Opens a VCD device or file initializes, a list of
729 tracks, segements and entry lsns and sizes and returns an opaque handle.
730 *****************************************************************************/
731 static vcdinfo_obj_t *
732 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
734 access_t *p_access = (access_t *)p_this;
735 vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
736 vcdinfo_obj_t *p_vcdobj;
740 dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
742 if( !psz_dev ) return NULL;
744 actual_dev= ToLocaleDup(psz_dev);
745 if( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
754 Save summary info on tracks, segments and entries...
757 if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) )
759 p_vcdplayer->track = (vcdplayer_play_item_info_t *)
760 calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
762 for (i=0; i<p_vcdplayer->i_tracks; i++)
764 unsigned int track_num=i+1;
765 p_vcdplayer->track[i].size =
766 vcdinfo_get_track_sect_count(p_vcdobj, track_num);
767 p_vcdplayer->track[i].start_LSN =
768 vcdinfo_get_track_lsn(p_vcdobj, track_num);
771 p_vcdplayer->track = NULL;
773 if( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) )
775 p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
776 calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
778 for (i=0; i<p_vcdplayer->i_entries; i++)
780 p_vcdplayer->entry[i].size =
781 vcdinfo_get_entry_sect_count(p_vcdobj, i);
782 p_vcdplayer->entry[i].start_LSN =
783 vcdinfo_get_entry_lsn(p_vcdobj, i);
786 p_vcdplayer->entry = NULL;
788 if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) )
790 p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
791 calloc(p_vcdplayer->i_segments, sizeof(vcdplayer_play_item_info_t));
793 for (i=0; i<p_vcdplayer->i_segments; i++)
795 p_vcdplayer->segment[i].size =
796 vcdinfo_get_seg_sector_count(p_vcdobj, i);
797 p_vcdplayer->segment[i].start_LSN =
798 vcdinfo_get_seg_lsn(p_vcdobj, i);
801 p_vcdplayer->segment = NULL;
806 /****************************************************************************
807 Update the "varname" variable to i_num without triggering a callback.
808 ****************************************************************************/
810 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
811 const char *p_varname, char *p_label,
812 const char *p_debug_label)
818 const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
819 dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
824 text.psz_string = p_label;
825 var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
827 var_Change( p_access, p_varname, i_action, &val, NULL );
831 /*****************************************************************************
833 *****************************************************************************/
835 /*****************************************************************************
837 read in meta-information about VCD: the number of tracks, segments,
838 entries, size and starting information. Then set up state variables so
839 that we read/seek starting at the location specified.
841 On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
842 and VLC_EGENERIC for some other error.
843 *****************************************************************************/
845 VCDOpen ( vlc_object_t *p_this )
847 access_t *p_access = (access_t *)p_this;
848 vcdplayer_t *p_vcdplayer;
850 vcdinfo_itemid_t itemid;
851 bool play_single_item = false;
853 p_access->pf_read = NULL;
854 p_access->pf_block = VCDReadBlock;
855 p_access->pf_control = VCDControl;
856 p_access->pf_seek = VCDSeek;
858 p_access->info.i_update = 0;
859 p_access->info.i_size = 0;
860 p_access->info.i_pos = 0;
861 p_access->info.b_eof = false;
862 p_access->info.i_title = 0;
863 p_access->info.i_seekpoint = 0;
865 p_vcdplayer = malloc( sizeof(vcdplayer_t) );
867 if( p_vcdplayer == NULL )
870 p_vcdplayer->i_debug = var_InheritInteger( p_this, MODULE_STRING "-debug" );
871 p_access->p_sys = (access_sys_t *) p_vcdplayer;
873 /* Set where to log errors messages from libcdio. */
874 p_vcd_access = p_access;
875 cdio_log_set_handler ( cdio_log_handler );
876 vcd_log_set_handler ( vcd_log_handler );
878 psz_source = VCDParse( p_access, &itemid, &play_single_item );
880 if ( NULL == psz_source )
883 return( VLC_EGENERIC );
886 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
887 psz_source, p_access->psz_location );
889 p_vcdplayer->psz_source = strdup(psz_source);
890 p_vcdplayer->i_blocks_per_read = var_InheritInteger( p_this, MODULE_STRING
891 "-blocks-per-read" );
892 p_vcdplayer->b_track_length = var_InheritInteger( p_this, MODULE_STRING
894 p_vcdplayer->in_still = false;
895 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
896 p_vcdplayer->p_input = access_GetParentInput( p_access );
897 // p_vcdplayer->p_meta = vlc_meta_New();
898 p_vcdplayer->p_segments = NULL;
899 p_vcdplayer->p_entries = NULL;
903 if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
908 p_vcdplayer->b_svd = vcdinfo_get_tracksSVD(p_vcdplayer->vcd);
910 /* Get track information. */
911 p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
913 if( p_vcdplayer->i_tracks<1 || CDIO_INVALID_TRACK==p_vcdplayer->i_tracks )
915 vcdinfo_close( p_vcdplayer->vcd );
916 LOG_ERR ("no movie tracks found" );
920 /* Build Navigation Title table for the tracks. */
921 VCDTitles( p_access );
923 /* Add into the above entry points as "Chapters". */
924 if( ! VCDEntryPoints( p_access ) )
926 msg_Warn( p_access, "could not read entry points, will not use them" );
927 p_vcdplayer->b_valid_ep = false;
930 /* Initialize LID info and add that as a menu item */
931 if( ! VCDLIDs( p_access ) )
933 msg_Warn( p_access, "could not read entry LIDs" );
936 /* Do we set PBC (via LID) on? */
938 ( VCDINFO_ITEM_TYPE_LID == itemid.type
939 && p_vcdplayer->i_lids > itemid.num )
941 : VCDINFO_INVALID_ENTRY;
943 /* Initialize segment information and add that a "Track". */
944 VCDSegments( p_access );
946 vcdplayer_play( p_access, itemid );
948 free( p_access->psz_demux );
949 p_access->psz_demux = strdup( "ps" );
952 if( play_single_item )
953 VCDFixupPlayList(p_access,p_vcd,psz_source,&itemid,play_single_item);
957 p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
958 p_vcdplayer->p_intf->b_block = false;
960 p_vcdplayer->p_access = p_access;
966 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
968 free( p_vcdplayer->psz_source );
973 /*****************************************************************************
974 * VCDClose: closes VCD releasing allocated memory.
975 *****************************************************************************/
977 VCDClose ( vlc_object_t *p_this )
979 access_t *p_access = (access_t *)p_this;
980 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
982 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
986 for (i=0 ; i<p_vcdplayer->i_titles; i++)
987 if (p_vcdplayer->p_title[i])
988 free(p_vcdplayer->p_title[i]->psz_name);
991 vcdinfo_close( p_vcdplayer->vcd );
993 if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
995 FREENULL( p_vcdplayer->p_entries );
996 FREENULL( p_vcdplayer->p_segments );
997 FREENULL( p_vcdplayer->psz_source );
998 FREENULL( p_vcdplayer->track );
999 FREENULL( p_vcdplayer->segment );
1000 FREENULL( p_vcdplayer->entry );
1001 FREENULL( p_access->psz_demux );
1002 FREENULL( p_vcdplayer );
1003 p_vcd_access = NULL;
1006 /*****************************************************************************
1007 * Control: The front-end or vlc engine calls here to ether get
1008 * information such as meta information or plugin capabilities or to
1009 * issue miscellaneous "set" requests.
1010 *****************************************************************************/
1011 static int VCDControl( access_t *p_access, int i_query, va_list args )
1013 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
1017 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
1018 "query %d", i_query );
1022 /* Pass back a copy of meta information that was gathered when we
1023 during the Open/Initialize call.
1025 case ACCESS_GET_META:
1026 dbg_print( INPUT_DBG_EVENT, "get meta info" );
1028 if( p_vcdplayer->p_meta )
1030 vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg(args,vlc_meta_t**);
1032 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
1033 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
1037 msg_Warn( p_access, "tried to copy NULL meta info" );
1041 case ACCESS_CAN_SEEK:
1042 case ACCESS_CAN_FASTSEEK:
1043 case ACCESS_CAN_PAUSE:
1044 case ACCESS_CAN_CONTROL_PACE:
1046 dbg_print( INPUT_DBG_EVENT,
1047 "seek/fastseek/pause/can_control_pace" );
1048 *((bool*)va_arg( args, bool* )) = true;
1052 case ACCESS_GET_PTS_DELAY:
1053 *(int64_t*)va_arg(args,int64_t *) = INT64_C(1000) *
1054 var_GetInteger( p_access, MODULE_STRING "-caching" );
1055 dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
1059 case ACCESS_SET_PAUSE_STATE:
1060 dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
1063 case ACCESS_GET_TITLE_INFO:
1065 unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
1066 + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
1067 input_title_t ***ppp_title
1068 = (input_title_t***)va_arg( args, input_title_t*** );
1069 char *psz_mrl = malloc( psz_mrl_max );
1072 pi_int = (int*)va_arg( args, int* );
1074 dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
1075 p_vcdplayer->i_titles );
1079 snprintf(psz_mrl, psz_mrl_max, "%s%s",
1080 VCD_MRL_PREFIX, p_vcdplayer->psz_source);
1081 VCDMetaInfo( p_access, psz_mrl );
1085 /* Duplicate title info */
1086 if( p_vcdplayer->i_titles == 0 )
1088 *pi_int = 0; ppp_title = NULL;
1091 *pi_int = p_vcdplayer->i_titles;
1092 *ppp_title = malloc(sizeof(input_title_t **)*p_vcdplayer->i_titles);
1094 if (!*ppp_title) return VLC_ENOMEM;
1096 for( i = 0; i < p_vcdplayer->i_titles; i++ )
1097 if( p_vcdplayer->p_title[i] )
1099 vlc_input_title_Duplicate(p_vcdplayer->p_title[i]);
1103 case ACCESS_SET_TITLE:
1104 i = (int)va_arg( args, int );
1106 dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
1107 if( i != p_access->info.i_title )
1109 vcdinfo_itemid_t itemid;
1110 track_t i_track = i+1;
1111 unsigned int i_entry =
1112 vcdinfo_track_get_entry(p_vcdplayer->vcd,i_track);
1114 if( i < p_vcdplayer->i_tracks )
1116 /* FIXME! For now we are assuming titles are only
1117 tracks and that track == title+1 */
1118 itemid.num = i_track;
1119 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
1123 /* FIXME! i_tracks+2 are Segments, but we need to be able
1124 to figure out which segment of that. i_tracks+1 is
1125 either Segments (if no LIDs) or LIDs otherwise. Again
1126 need a way to get the LID number. */
1128 msg_Warn(p_access,"Trying to set track (%u) beyond end "
1129 "of last track (%u).",i+1,p_vcdplayer->i_tracks);
1130 return VLC_EGENERIC;
1133 VCDSetOrigin(p_access,
1134 vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i_entry),
1139 case ACCESS_SET_SEEKPOINT:
1141 input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
1142 unsigned int i = (unsigned int)va_arg( args, unsigned int );
1144 dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
1145 if( t->i_seekpoint > 0 )
1147 track_t i_track = p_access->info.i_title+1;
1150 /* FIXME! For now we are assuming titles are only tracks and
1151 that track == title+1 and we the play item is entries (not
1152 tracks or lids). We need to generalize all of this.
1155 if (i < p_vcdplayer->i_entries)
1157 p_vcdplayer->play_item.num = i;
1158 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
1159 lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
1160 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
1162 p_vcdplayer->play_item.num = i = i - p_vcdplayer->i_entries;
1163 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
1167 p_vcdplayer->play_item.num = i
1168 = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
1169 p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
1170 lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
1173 VCDSetOrigin(p_access,vcdinfo_get_entry_lsn(p_vcdplayer->vcd,i),
1174 i_track,&(p_vcdplayer->play_item));
1179 case ACCESS_SET_PRIVATE_ID_STATE:
1180 dbg_print( INPUT_DBG_EVENT, "set private id" );
1181 return VLC_EGENERIC;
1184 msg_Warn( p_access, "unimplemented query in control" );
1185 return VLC_EGENERIC;