1 /*****************************************************************************
2 * vcdplayer.c : VCD input module for vlc
3 * using libcdio, libvcd and libvcdinfo
4 *****************************************************************************
5 * Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
21 *****************************************************************************/
24 This contains more of the vlc-independent parts that might be used
25 in any VCD input module for a media player. However at present there
26 are vlc-specific structures. See also vcdplayer.c of the xine plugin.
28 /*****************************************************************************
30 *****************************************************************************/
33 #include <vlc/input.h>
37 #include "vcdplayer.h"
42 #include <cdio/cdio.h>
43 #include <cdio/util.h>
44 #include <libvcd/info.h>
47 #define sleep(A) Sleep((A)*1000)
50 extern void VCDSetOrigin ( access_t *p_access, lsn_t i_lsn, track_t i_track,
51 const vcdinfo_itemid_t * p_itemid );
54 Return VLC_TRUE if playback control (PBC) is on
57 vcdplayer_pbc_is_on( const vcdplayer_t *p_vcd )
59 return VCDINFO_INVALID_ENTRY != p_vcd->i_lid;
62 /* Given an itemid, return the size for the object (via information
63 previously stored when opening the vcd). */
65 vcdplayer_get_item_size(access_t * p_access, vcdinfo_itemid_t itemid)
67 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
69 switch (itemid.type) {
70 case VCDINFO_ITEM_TYPE_ENTRY:
71 return p_vcd->entry[itemid.num].size;
73 case VCDINFO_ITEM_TYPE_SEGMENT:
74 return p_vcd->segment[itemid.num].size;
76 case VCDINFO_ITEM_TYPE_TRACK:
77 return p_vcd->track[itemid.num-1].size;
79 case VCDINFO_ITEM_TYPE_LID:
80 /* Play list number (LID) */
83 case VCDINFO_ITEM_TYPE_NOTFOUND:
84 case VCDINFO_ITEM_TYPE_SPAREID2:
86 LOG_ERR("%s %d", _("bad item type"), itemid.type);
92 vcdplayer_update_entry( access_t * p_access, uint16_t ofs,
93 uint16_t *entry, const char *label)
95 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
97 if ( ofs == VCDINFO_INVALID_OFFSET ) {
98 *entry = VCDINFO_INVALID_ENTRY;
100 vcdinfo_offset_t *off = vcdinfo_get_offset_t(p_vcd->vcd, ofs);
103 dbg_print(INPUT_DBG_PBC, "%s: LID %d", label, off->lid);
105 *entry = VCDINFO_INVALID_ENTRY;
109 /* Handles navigation when NOT in PBC reaching the end of a play item.
111 The navigations rules here may be sort of made up, but the intent
112 is to do something that's probably right or helpful.
114 return VLC_TRUE if the caller should return.
116 vcdplayer_read_status_t
117 vcdplayer_non_pbc_nav ( access_t *p_access )
119 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
121 /* Not in playback control. Do we advance automatically or stop? */
122 switch (p_vcd->play_item.type) {
123 case VCDINFO_ITEM_TYPE_TRACK:
124 case VCDINFO_ITEM_TYPE_ENTRY: {
125 if ( ! vcdplayer_play_next( p_access ) )
131 case VCDINFO_ITEM_TYPE_SPAREID2:
132 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
137 return READ_STILL_FRAME ;
140 case VCDINFO_ITEM_TYPE_NOTFOUND:
141 LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen");
143 case VCDINFO_ITEM_TYPE_LID:
144 LOG_ERR ("LID outside PBC -- not supposed to happen");
146 case VCDINFO_ITEM_TYPE_SEGMENT:
147 /* Hack: Just go back and do still again */
151 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
152 "End of Segment - looping" );
153 return READ_STILL_FRAME;
161 Set reading to play an entire track.
164 _vcdplayer_set_track(access_t * p_access, track_t i_track)
166 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
167 if (i_track < 1 || i_track > p_vcd->i_tracks)
170 vcdinfo_obj_t *p_obj = p_vcd->vcd;
171 vcdinfo_itemid_t itemid;
173 itemid.num = i_track;
174 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
177 VCDSetOrigin(p_access, vcdinfo_get_track_lsn(p_obj, i_track),
180 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcd->i_lsn);
185 Set reading to play an entry
188 _vcdplayer_set_entry(access_t * p_access, unsigned int num)
190 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
191 vcdinfo_obj_t *p_obj = p_vcd->vcd;
192 unsigned int num_entries = vcdinfo_get_num_entries(p_obj);
194 if (num >= num_entries) {
195 LOG_ERR("%s %d", _("bad entry number"), num);
198 vcdinfo_itemid_t itemid;
201 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
204 VCDSetOrigin(p_access, vcdinfo_get_entry_lba(p_obj, num),
205 vcdinfo_get_track(p_obj, num), &itemid);
207 dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u",
208 p_vcd->i_lsn, p_vcd->track_end_lsn);
213 Set reading to play an segment (e.g. still frame)
216 _vcdplayer_set_segment(access_t * p_access, unsigned int num)
218 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
219 vcdinfo_obj_t *p_obj = p_vcd->vcd;
220 segnum_t num_segs = vcdinfo_get_num_segments(p_obj);
222 if (num >= num_segs) {
223 LOG_ERR("%s %d", _("bad segment number"), num);
226 vcdinfo_itemid_t itemid;
228 if (VCDINFO_NULL_LSN==p_vcd->i_lsn) {
230 _("Error in getting current segment number"), num);
235 itemid.type = VCDINFO_ITEM_TYPE_SEGMENT;
237 VCDSetOrigin(p_access, vcdinfo_get_seg_lsn(p_obj, num), 0, &itemid);
239 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcd->i_lsn);
244 /* Play a single item. */
246 vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
248 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
249 vcdinfo_obj_t *p_obj = p_vcd->vcd;
251 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d, itemid.type: %d",
252 itemid.num, itemid.type);
256 switch (itemid.type) {
257 case VCDINFO_ITEM_TYPE_SEGMENT:
259 vcdinfo_video_segment_type_t segtype
260 = vcdinfo_get_video_type(p_obj, itemid.num);
261 segnum_t num_segs = vcdinfo_get_num_segments(p_obj);
263 dbg_print(INPUT_DBG_PBC, "%s (%d), itemid.num: %d",
264 vcdinfo_video_type2str(p_obj, itemid.num),
265 (int) segtype, itemid.num);
267 if (itemid.num >= num_segs) return;
268 _vcdplayer_set_segment(p_access, itemid.num);
272 case VCDINFO_FILES_VIDEO_NTSC_STILL:
273 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
274 case VCDINFO_FILES_VIDEO_PAL_STILL:
275 case VCDINFO_FILES_VIDEO_PAL_STILL2:
276 p_vcd->in_still = -5;
285 case VCDINFO_ITEM_TYPE_TRACK:
286 dbg_print(INPUT_DBG_PBC, "track %d", itemid.num);
287 if (itemid.num < 1 || itemid.num > p_vcd->i_tracks) return;
288 _vcdplayer_set_track(p_access, itemid.num);
291 case VCDINFO_ITEM_TYPE_ENTRY:
293 unsigned int num_entries = vcdinfo_get_num_entries(p_obj);
294 dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num);
295 if (itemid.num >= num_entries) return;
296 _vcdplayer_set_entry(p_access, itemid.num);
300 case VCDINFO_ITEM_TYPE_LID:
301 LOG_ERR("%s", _("Should have converted p_vcd above"));
304 case VCDINFO_ITEM_TYPE_NOTFOUND:
305 dbg_print(INPUT_DBG_PBC, "play nothing");
306 p_vcd->i_lsn = p_vcd->end_lsn;
310 LOG_ERR("item type %d not implemented.", itemid.type);
314 p_vcd->play_item = itemid;
316 /* Some players like xine, have a fifo queue of audio and video buffers
317 that need to be flushed when playing a new selection. */
318 /* if (p_vcd->flush_buffers)
319 p_vcd->flush_buffers(); */
323 Set's start origin and size for subsequent seeks.
324 input: p_vcd->i_lsn, p_vcd->play_item
325 changed: p_vcd->origin_lsn, p_vcd->end_lsn
328 /* FIXME: add parameters lsn, i_track, p_itemid and set accordingly. */
330 vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track,
331 const vcdinfo_itemid_t *p_itemid)
333 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
334 const size_t i_size= vcdplayer_get_item_size(p_access, *p_itemid);
336 p_vcd->play_item.num = p_itemid->num;
337 p_vcd->play_item.type = p_itemid->type;
338 p_vcd->i_lsn = i_lsn;
339 p_vcd->end_lsn = p_vcd->i_lsn + i_size;
340 p_vcd->origin_lsn = p_vcd->i_lsn;
341 p_vcd->i_track = i_track;
342 p_vcd->track_lsn = vcdinfo_get_track_lba(p_vcd->vcd, i_track);
344 dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN),
345 "lsn %u, end LSN: %u item.num %d, item.type %d",
346 p_vcd->i_lsn, p_vcd->end_lsn,
347 p_vcd->play_item.num, p_vcd->play_item.type);
351 Get the next play-item in the list given in the LIDs. Note play-item
352 here refers to list of play-items for a single LID It shouldn't be
353 confused with a user's list of favorite things to play or the
354 "next" field of a LID which moves us to a different LID.
357 _vcdplayer_inc_play_item(access_t *p_access)
359 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
362 dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcd->pdi);
364 if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return false;
366 noi = vcdinf_pld_get_noi(p_vcd->pxd.pld);
368 if ( noi <= 0 ) return false;
370 /* Handle delays like autowait or wait here? */
374 if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return false;
377 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld,
379 vcdinfo_itemid_t trans_itemid;
381 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
383 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
384 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
385 p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num));
386 vcdplayer_play_single_item(p_access, trans_itemid);
392 vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid)
394 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
396 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d itemid.type: %d",
397 itemid.num, itemid.type);
399 if (!vcdplayer_pbc_is_on(p_vcd)) {
400 vcdplayer_play_single_item(p_access, itemid);
402 /* PBC on - Itemid.num is LID. */
404 vcdinfo_obj_t *obj = p_vcd->vcd;
406 if (obj == NULL) return;
408 p_vcd->i_lid = itemid.num;
409 vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), itemid.num);
411 switch (p_vcd->pxd.descriptor_type) {
413 case PSD_TYPE_SELECTION_LIST:
414 case PSD_TYPE_EXT_SELECTION_LIST: {
415 vcdinfo_itemid_t trans_itemid;
416 uint16_t trans_itemid_num;
418 if (p_vcd->pxd.psd == NULL) return;
419 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
420 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
421 p_vcd->loop_count = 1;
422 p_vcd->loop_item = trans_itemid;
423 vcdplayer_play_single_item(p_access, trans_itemid);
427 case PSD_TYPE_PLAY_LIST: {
428 if (p_vcd->pxd.pld == NULL) return;
430 _vcdplayer_inc_play_item(p_access);
434 case PSD_TYPE_END_LIST:
435 case PSD_TYPE_COMMAND_LIST:
443 /* Handles PBC navigation when reaching the end of a play item. */
444 vcdplayer_read_status_t
445 vcdplayer_pbc_nav ( access_t * p_access )
447 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
449 /* We are in playback control. */
450 vcdinfo_itemid_t itemid;
452 /* The end of an entry is really the end of the associated
453 sequence (or track). */
455 if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type) &&
456 (p_vcd->i_lsn < p_vcd->end_lsn) ) {
457 /* Set up to just continue to the next entry */
458 p_vcd->play_item.num++;
459 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
460 "continuing into next entry: %u", p_vcd->play_item.num);
461 vcdplayer_play( p_access, p_vcd->play_item );
462 /* p_vcd->update_title(); */
466 switch (p_vcd->pxd.descriptor_type) {
467 case PSD_TYPE_END_LIST:
470 case PSD_TYPE_PLAY_LIST: {
471 int wait_time = vcdinf_get_wait_time(p_vcd->pxd.pld);
473 dbg_print(INPUT_DBG_PBC, "playlist wait_time: %d", wait_time);
475 if (vcdplayer_inc_play_item(p_access))
478 /* Handle any wait time given. */
480 if (p_vcd->in_still) {
481 vcdIntfStillTime( p_vcd->p_intf, wait_time );
482 return READ_STILL_FRAME;
486 vcdplayer_update_entry( p_access,
487 vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
488 &itemid.num, "next" );
489 itemid.type = VCDINFO_ITEM_TYPE_LID;
490 vcdplayer_play( p_access, itemid );
493 case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
494 case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
496 int wait_time = vcdinf_get_timeout_time(p_vcd->pxd.psd);
497 uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcd->pxd.psd);
498 uint16_t max_loop = vcdinf_get_loop_count(p_vcd->pxd.psd);
499 vcdinfo_offset_t *offset_timeout_LID =
500 vcdinfo_get_offset_t(p_vcd->vcd, timeout_offs);
502 dbg_print(INPUT_DBG_PBC, "wait_time: %d, looped: %d, max_loop %d",
503 wait_time, p_vcd->loop_count, max_loop);
505 /* Handle any wait time given */
507 if (p_vcd->in_still) {
508 vcdIntfStillTime( p_vcd->p_intf, wait_time );
509 return READ_STILL_FRAME;
513 /* Handle any looping given. */
514 if ( max_loop == 0 || p_vcd->loop_count < max_loop ) {
516 if (p_vcd->loop_count == 0x7f) p_vcd->loop_count = 0;
517 VCDSeek( p_access, 0 );
518 /* if (p_vcd->in_still) p_vcd->force_redisplay();*/
522 /* Looping finished and wait finished. Move to timeout
523 entry or next entry, or handle still. */
525 if (NULL != offset_timeout_LID) {
526 /* Handle timeout_LID */
527 itemid.num = offset_timeout_LID->lid;
528 itemid.type = VCDINFO_ITEM_TYPE_LID;
529 dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
530 vcdplayer_play( p_access, itemid );
533 int num_selections = vcdinf_get_num_selections(p_vcd->pxd.psd);
534 if (num_selections > 0) {
535 /* Pick a random selection. */
536 unsigned int bsn=vcdinf_get_bsn(p_vcd->pxd.psd);
537 int rand_selection=bsn +
538 (int) ((num_selections+0.0)*rand()/(RAND_MAX+1.0));
539 lid_t rand_lid=vcdinfo_selection_get_lid (p_vcd->vcd,
542 itemid.num = rand_lid;
543 itemid.type = VCDINFO_ITEM_TYPE_LID;
544 dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
545 rand_selection - bsn, rand_lid);
546 vcdplayer_play( p_access, itemid );
548 } else if (p_vcd->in_still) {
549 /* Hack: Just go back and do still again */
551 return READ_STILL_FRAME;
556 case VCDINFO_ITEM_TYPE_NOTFOUND:
557 LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
559 case VCDINFO_ITEM_TYPE_SPAREID2:
560 LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
562 case VCDINFO_ITEM_TYPE_LID:
563 LOG_ERR( "LID in PBC -- not supposed to happen" );
569 /* FIXME: Should handle autowait ... */
575 Read block into p_buf and return the status back.
577 This routine is a bit complicated because on reaching the end of
578 a track or entry we may automatically advance to the item, or
579 interpret the next item in the playback-control list.
581 vcdplayer_read_status_t
582 vcdplayer_read (access_t * p_access, uint8_t *p_buf)
585 /* p_access->handle_events (); */
587 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
588 if ( p_vcd->i_lsn >= p_vcd->end_lsn ) {
589 vcdplayer_read_status_t read_status;
591 /* We've run off of the end of this entry. Do we continue or stop? */
592 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
593 "end reached, cur: %u, end: %u\n", p_vcd->i_lsn, p_vcd->end_lsn);
595 handle_item_continuation:
596 read_status = vcdplayer_pbc_is_on( p_vcd )
597 ? vcdplayer_pbc_nav( p_access )
598 : vcdplayer_non_pbc_nav( p_access );
600 if (READ_BLOCK != read_status) return read_status;
603 /* Read the next block.
605 Important note: we probably speed things up by removing "data"
606 and the memcpy to it by extending vcd_image_source_read_mode2
607 to allow a mode to do what's below in addition to its
608 "raw" and "block" mode. It also would probably improve the modularity
609 a little bit as well.
613 CdIo *p_img = vcdinfo_get_cd_image(p_vcd->vcd);
615 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
616 uint8_t data [M2F2_SECTOR_SIZE];
619 vcdsector_t vcd_sector;
622 if (cdio_read_mode2_sector(p_img, &vcd_sector, p_vcd->i_lsn, true)!=0) {
623 dbg_print(INPUT_DBG_LSN, "read error\n");
628 if ( p_vcd->i_lsn >= p_vcd->end_lsn ) {
629 /* We've run off of the end of p_vcd entry. Do we continue or stop? */
630 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
631 "end reached in reading, cur: %u, end: %u\n",
632 p_vcd->i_lsn, p_vcd->end_lsn);
636 /* Check header ID for a padding sector and simply discard
637 these. It is alleged that VCD's put these in to keep the
640 } while((vcd_sector.subheader[2]&~0x01)==0x60);
642 if ( p_vcd->i_lsn >= p_vcd->end_lsn )
643 /* We've run off of the end of this entry. Do we continue or stop? */
644 goto handle_item_continuation;
646 memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE);
652 Get the next play-item in the list given in the LIDs. Note play-item
653 here refers to list of play-items for a single LID It shouldn't be
654 confused with a user's list of favorite things to play or the
655 "next" field of a LID which moves us to a different LID.
658 vcdplayer_inc_play_item( access_t *p_access )
660 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
664 dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcd->pdi);
666 if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return VLC_FALSE;
668 noi = vcdinf_pld_get_noi(p_vcd->pxd.pld);
670 if ( noi <= 0 ) return VLC_FALSE;
672 /* Handle delays like autowait or wait here? */
676 if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return VLC_FALSE;
679 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld,
681 vcdinfo_itemid_t trans_itemid;
683 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return VLC_FALSE;
685 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
686 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
687 p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num));
688 vcdplayer_play( p_access, trans_itemid );
694 Play item assocated with the "default" selection.
696 Return VLC_FALSE if there was some problem.
699 vcdplayer_play_default( access_t * p_access )
701 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
703 vcdinfo_itemid_t itemid;
706 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
712 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
713 "current: %d" , p_vcd->play_item.num);
715 itemid.type = p_vcd->play_item.type;
717 if (vcdplayer_pbc_is_on(p_vcd)) {
719 #if defined(LIBVCD_VERSION)
720 lid_t lid=vcdinfo_get_multi_default_lid(p_vcd->vcd, p_vcd->i_lid,
723 if (VCDINFO_INVALID_LID != lid) {
725 itemid.type = VCDINFO_ITEM_TYPE_LID;
726 dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num);
728 dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcd->i_lid);
732 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), p_vcd->i_lid);
734 switch (p_vcd->pxd.descriptor_type) {
735 case PSD_TYPE_SELECTION_LIST:
736 case PSD_TYPE_EXT_SELECTION_LIST:
737 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
738 vcdplayer_update_entry( p_access,
739 vcdinfo_get_default_offset(p_vcd->vcd,
741 &itemid.num, "default");
744 case PSD_TYPE_PLAY_LIST:
745 case PSD_TYPE_END_LIST:
746 case PSD_TYPE_COMMAND_LIST:
747 LOG_WARN( "There is no PBC 'default' selection here" );
750 #endif /* LIBVCD_VERSION (< 0.7.21) */
755 /* PBC is not on. "default" selection beginning of current
758 p_vcd->play_item.num = p_vcd->play_item.num;
762 /** ??? p_vcd->update_title(); ***/
763 vcdplayer_play( p_access, itemid );
769 Play item assocated with the "next" selection.
771 Return VLC_FALSE if there was some problem.
774 vcdplayer_play_next( access_t * p_access )
776 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
778 vcdinfo_obj_t *p_obj;
779 vcdinfo_itemid_t itemid;
781 if (!p_vcd) return VLC_FALSE;
783 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
784 "current: %d" , p_vcd->play_item.num);
788 itemid.type = p_vcd->play_item.type;
790 if (vcdplayer_pbc_is_on(p_vcd)) {
792 vcdinfo_lid_get_pxd(p_obj, &(p_vcd->pxd), p_vcd->i_lid);
794 switch (p_vcd->pxd.descriptor_type) {
795 case PSD_TYPE_SELECTION_LIST:
796 case PSD_TYPE_EXT_SELECTION_LIST:
797 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
798 vcdplayer_update_entry( p_access,
799 vcdinf_psd_get_next_offset(p_vcd->pxd.psd),
800 &itemid.num, "next");
801 itemid.type = VCDINFO_ITEM_TYPE_LID;
804 case PSD_TYPE_PLAY_LIST:
805 if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
806 vcdplayer_update_entry( p_access,
807 vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
808 &itemid.num, "next");
809 itemid.type = VCDINFO_ITEM_TYPE_LID;
812 case PSD_TYPE_END_LIST:
813 case PSD_TYPE_COMMAND_LIST:
814 LOG_WARN( "There is no PBC 'next' selection here" );
819 /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
823 switch (p_vcd->play_item.type) {
824 case VCDINFO_ITEM_TYPE_ENTRY:
825 case VCDINFO_ITEM_TYPE_SEGMENT:
826 case VCDINFO_ITEM_TYPE_TRACK:
828 switch (p_vcd->play_item.type) {
829 case VCDINFO_ITEM_TYPE_ENTRY:
830 max_entry = p_vcd->i_entries;
832 case VCDINFO_ITEM_TYPE_SEGMENT:
833 max_entry = p_vcd->i_segments;
835 case VCDINFO_ITEM_TYPE_TRACK:
836 max_entry = p_vcd->i_tracks;
838 default: ; /* Handle exceptional cases below */
841 if (p_vcd->play_item.num+1 < max_entry) {
842 itemid.num = p_vcd->play_item.num+1;
844 LOG_WARN( "At the end - non-PBC 'next' not possible here" );
850 case VCDINFO_ITEM_TYPE_LID:
852 /* Should have handled above. */
853 LOG_WARN( "Internal inconsistency - should not have gotten here." );
861 /** ??? p_vcd->update_title(); ***/
862 vcdplayer_play( p_access, itemid );
868 Play item assocated with the "prev" selection.
870 Return VLC_FALSE if there was some problem.
873 vcdplayer_play_prev( access_t * p_access )
875 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
876 vcdinfo_obj_t *p_obj = p_vcd->vcd;
877 vcdinfo_itemid_t itemid;
879 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
880 "current: %d" , p_vcd->play_item.num);
882 itemid.type = p_vcd->play_item.type;
884 if (vcdplayer_pbc_is_on(p_vcd)) {
886 vcdinfo_lid_get_pxd(p_obj, &(p_vcd->pxd), p_vcd->i_lid);
888 switch (p_vcd->pxd.descriptor_type) {
889 case PSD_TYPE_SELECTION_LIST:
890 case PSD_TYPE_EXT_SELECTION_LIST:
891 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
892 vcdplayer_update_entry( p_access,
893 vcdinf_psd_get_prev_offset(p_vcd->pxd.psd),
894 &itemid.num, "prev");
895 itemid.type = VCDINFO_ITEM_TYPE_LID;
898 case PSD_TYPE_PLAY_LIST:
899 if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
900 vcdplayer_update_entry( p_access,
901 vcdinf_pld_get_prev_offset(p_vcd->pxd.pld),
902 &itemid.num, "prev");
903 itemid.type = VCDINFO_ITEM_TYPE_LID;
906 case PSD_TYPE_END_LIST:
907 case PSD_TYPE_COMMAND_LIST:
908 LOG_WARN( "There is no PBC 'prev' selection here" );
913 /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
915 int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type)
918 if (p_vcd->play_item.num > min_entry) {
919 itemid.num = p_vcd->play_item.num-1;
921 LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
927 /** ??? p_vcd->update_title(); ***/
928 vcdplayer_play( p_access, itemid );
934 Play item assocated with the "return" selection.
936 Return VLC_FALSE if there was some problem.
939 vcdplayer_play_return( access_t * p_access )
941 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
942 vcdinfo_obj_t *p_obj = p_vcd->vcd;
943 vcdinfo_itemid_t itemid;
945 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
946 "current: %d" , p_vcd->play_item.num);
948 itemid.type = p_vcd->play_item.type;
950 if (vcdplayer_pbc_is_on(p_vcd)) {
952 vcdinfo_lid_get_pxd(p_obj, &(p_vcd->pxd), p_vcd->i_lid);
954 switch (p_vcd->pxd.descriptor_type) {
955 case PSD_TYPE_SELECTION_LIST:
956 case PSD_TYPE_EXT_SELECTION_LIST:
957 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
958 vcdplayer_update_entry( p_access,
959 vcdinf_psd_get_return_offset(p_vcd->pxd.psd),
960 &itemid.num, "return");
961 itemid.type = VCDINFO_ITEM_TYPE_LID;
964 case PSD_TYPE_PLAY_LIST:
965 if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
966 vcdplayer_update_entry( p_access,
967 vcdinf_pld_get_return_offset(p_vcd->pxd.pld),
968 &itemid.num, "return");
969 itemid.type = VCDINFO_ITEM_TYPE_LID;
972 case PSD_TYPE_END_LIST:
973 case PSD_TYPE_COMMAND_LIST:
974 LOG_WARN( "There is no PBC 'return' selection here" );
979 /* PBC is not on. "Return" selection is min_entry if possible. */
981 p_vcd->play_item.num = (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type)
986 /** ??? p_vcd->update_title(); ***/
987 vcdplayer_play( p_access, itemid );