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 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 true if the caller should return.
116 vcdplayer_read_status_t
117 vcdplayer_non_pbc_nav ( access_t *p_access, uint8_t *wait_time )
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),
136 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
137 "End of still spareid2" );
139 return READ_STILL_FRAME ;
142 case VCDINFO_ITEM_TYPE_NOTFOUND:
143 LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen");
145 case VCDINFO_ITEM_TYPE_LID:
146 LOG_ERR ("LID outside PBC -- not supposed to happen");
148 case VCDINFO_ITEM_TYPE_SEGMENT:
149 /* Hack: Just go back and do still again */
153 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
154 "End of still Segment" );
156 return READ_STILL_FRAME;
164 Set reading to play an entire track.
167 _vcdplayer_set_track(access_t * p_access, track_t i_track)
169 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
170 if (i_track < 1 || i_track > p_vcd->i_tracks)
173 vcdinfo_obj_t *p_obj = p_vcd->vcd;
174 vcdinfo_itemid_t itemid;
176 itemid.num = i_track;
177 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
180 VCDSetOrigin(p_access, vcdinfo_get_track_lsn(p_obj, i_track),
183 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcd->i_lsn);
188 Set reading to play an entry
191 _vcdplayer_set_entry(access_t * p_access, unsigned int num)
193 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
194 vcdinfo_obj_t *p_obj = p_vcd->vcd;
195 unsigned int num_entries = vcdinfo_get_num_entries(p_obj);
197 if (num >= num_entries) {
198 LOG_ERR("%s %d", _("bad entry number"), num);
201 vcdinfo_itemid_t itemid;
204 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
207 VCDSetOrigin(p_access, vcdinfo_get_entry_lba(p_obj, num),
208 vcdinfo_get_track(p_obj, num), &itemid);
210 dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u",
211 p_vcd->i_lsn, p_vcd->track_end_lsn);
216 Set reading to play an segment (e.g. still frame)
219 _vcdplayer_set_segment(access_t * p_access, unsigned int num)
221 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
222 vcdinfo_obj_t *p_obj = p_vcd->vcd;
223 segnum_t num_segs = vcdinfo_get_num_segments(p_obj);
225 if (num >= num_segs) {
226 LOG_ERR("%s %d", _("bad segment number"), num);
229 vcdinfo_itemid_t itemid;
231 if (VCDINFO_NULL_LSN==p_vcd->i_lsn) {
233 _("Error in getting current segment number"), num);
238 itemid.type = VCDINFO_ITEM_TYPE_SEGMENT;
240 VCDSetOrigin(p_access, vcdinfo_get_seg_lsn(p_obj, num), 0, &itemid);
242 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcd->i_lsn);
247 /* Play a single item. */
249 vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
251 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
252 vcdinfo_obj_t *p_obj = p_vcd->vcd;
254 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d, itemid.type: %d",
255 itemid.num, itemid.type);
259 switch (itemid.type) {
260 case VCDINFO_ITEM_TYPE_SEGMENT:
262 vcdinfo_video_segment_type_t segtype
263 = vcdinfo_get_video_type(p_obj, itemid.num);
264 segnum_t num_segs = vcdinfo_get_num_segments(p_obj);
266 dbg_print(INPUT_DBG_PBC, "%s (%d), itemid.num: %d",
267 vcdinfo_video_type2str(p_obj, itemid.num),
268 (int) segtype, itemid.num);
270 if (itemid.num >= num_segs) return false;
271 _vcdplayer_set_segment(p_access, itemid.num);
275 case VCDINFO_FILES_VIDEO_NTSC_STILL:
276 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
277 case VCDINFO_FILES_VIDEO_PAL_STILL:
278 case VCDINFO_FILES_VIDEO_PAL_STILL2:
279 p_vcd->in_still = -5;
288 case VCDINFO_ITEM_TYPE_TRACK:
289 dbg_print(INPUT_DBG_PBC, "track %d", itemid.num);
290 if (itemid.num < 1 || itemid.num > p_vcd->i_tracks) return false;
291 _vcdplayer_set_track(p_access, itemid.num);
294 case VCDINFO_ITEM_TYPE_ENTRY:
296 unsigned int num_entries = vcdinfo_get_num_entries(p_obj);
297 dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num);
298 if (itemid.num >= num_entries) return false;
299 _vcdplayer_set_entry(p_access, itemid.num);
303 case VCDINFO_ITEM_TYPE_LID:
304 LOG_ERR("%s", _("Should have converted p_vcd above"));
308 case VCDINFO_ITEM_TYPE_NOTFOUND:
309 dbg_print(INPUT_DBG_PBC, "play nothing");
310 p_vcd->i_lsn = p_vcd->end_lsn;
314 LOG_ERR("item type %d not implemented.", itemid.type);
318 p_vcd->play_item = itemid;
320 /* Some players like xine, have a fifo queue of audio and video buffers
321 that need to be flushed when playing a new selection. */
322 /* if (p_vcd->flush_buffers)
323 p_vcd->flush_buffers(); */
328 Set's start origin and size for subsequent seeks.
329 input: p_vcd->i_lsn, p_vcd->play_item
330 changed: p_vcd->origin_lsn, p_vcd->end_lsn
333 /* FIXME: add parameters lsn, i_track, p_itemid and set accordingly. */
335 vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track,
336 const vcdinfo_itemid_t *p_itemid)
338 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
339 const size_t i_size= vcdplayer_get_item_size(p_access, *p_itemid);
341 p_vcd->play_item.num = p_itemid->num;
342 p_vcd->play_item.type = p_itemid->type;
343 p_vcd->i_lsn = i_lsn;
344 p_vcd->end_lsn = p_vcd->i_lsn + i_size;
345 p_vcd->origin_lsn = p_vcd->i_lsn;
346 p_vcd->i_track = i_track;
347 p_vcd->track_lsn = vcdinfo_get_track_lba(p_vcd->vcd, i_track);
349 dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN),
350 "lsn %u, end LSN: %u item.num %d, item.type %d",
351 p_vcd->i_lsn, p_vcd->end_lsn,
352 p_vcd->play_item.num, p_vcd->play_item.type);
356 Get the next play-item in the list given in the LIDs. Note play-item
357 here refers to list of play-items for a single LID It shouldn't be
358 confused with a user's list of favorite things to play or the
359 "next" field of a LID which moves us to a different LID.
362 _vcdplayer_inc_play_item(access_t *p_access)
364 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
367 dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcd->pdi);
369 if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return false;
371 noi = vcdinf_pld_get_noi(p_vcd->pxd.pld);
373 if ( noi <= 0 ) return false;
375 /* Handle delays like autowait or wait here? */
379 if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return false;
382 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld,
384 vcdinfo_itemid_t trans_itemid;
386 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
388 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
389 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
390 p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num));
391 return vcdplayer_play_single_item(p_access, trans_itemid);
396 vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid)
398 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
400 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d itemid.type: %d",
401 itemid.num, itemid.type);
403 if (!vcdplayer_pbc_is_on(p_vcd)) {
404 vcdplayer_play_single_item(p_access, itemid);
406 /* PBC on - Itemid.num is LID. */
408 vcdinfo_obj_t *obj = p_vcd->vcd;
410 if (obj == NULL) return;
412 p_vcd->i_lid = itemid.num;
413 vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), itemid.num);
415 switch (p_vcd->pxd.descriptor_type) {
417 case PSD_TYPE_SELECTION_LIST:
418 case PSD_TYPE_EXT_SELECTION_LIST: {
419 vcdinfo_itemid_t trans_itemid;
420 uint16_t trans_itemid_num;
422 if (p_vcd->pxd.psd == NULL) return;
423 trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
424 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
425 p_vcd->loop_count = 1;
426 p_vcd->loop_item = trans_itemid;
427 vcdplayer_play_single_item(p_access, trans_itemid);
431 case PSD_TYPE_PLAY_LIST: {
432 if (p_vcd->pxd.pld == NULL) return;
434 _vcdplayer_inc_play_item(p_access);
438 case PSD_TYPE_END_LIST:
439 case PSD_TYPE_COMMAND_LIST:
447 /* Handles PBC navigation when reaching the end of a play item. */
448 vcdplayer_read_status_t
449 vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time )
451 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
453 /* We are in playback control. */
454 vcdinfo_itemid_t itemid;
456 /* The end of an entry is really the end of the associated
457 sequence (or track). */
459 if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type) &&
460 (p_vcd->i_lsn < p_vcd->end_lsn) ) {
461 /* Set up to just continue to the next entry */
462 p_vcd->play_item.num++;
463 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
464 "continuing into next entry: %u", p_vcd->play_item.num);
465 vcdplayer_play( p_access, p_vcd->play_item );
466 /* p_vcd->update_title(); */
470 switch (p_vcd->pxd.descriptor_type) {
471 case PSD_TYPE_END_LIST:
474 case PSD_TYPE_PLAY_LIST: {
475 if (vcdplayer_inc_play_item(p_access))
478 /* Set up for caller process wait time given. */
479 if (p_vcd->in_still) {
480 *wait_time = vcdinf_get_wait_time(p_vcd->pxd.pld);
481 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
482 "playlist wait time: %d", *wait_time);
483 return READ_STILL_FRAME;
486 /* Wait time has been processed; continue with next entry. */
487 vcdplayer_update_entry( p_access,
488 vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
489 &itemid.num, "next" );
490 itemid.type = VCDINFO_ITEM_TYPE_LID;
491 vcdplayer_play( p_access, itemid );
494 case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
495 case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
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, "looped: %d, max_loop %d",
503 p_vcd->loop_count, max_loop);
505 /* Set up for caller process wait time given. */
506 if (p_vcd->in_still) {
507 *wait_time = vcdinf_get_timeout_time(p_vcd->pxd.psd);
508 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
509 "playlist wait_time: %d", *wait_time);
510 return READ_STILL_FRAME;
513 /* Wait time has been processed; continue with next entry. */
514 /* Handle any looping given. */
515 if ( max_loop == 0 || p_vcd->loop_count < max_loop ) {
517 if (p_vcd->loop_count == 0x7f) p_vcd->loop_count = 0;
518 VCDSeek( p_access, 0 );
519 /* if (p_vcd->in_still) p_vcd->force_redisplay();*/
523 /* Looping finished and wait finished. Move to timeout
524 entry or next entry, or handle still. */
526 if (NULL != offset_timeout_LID) {
527 /* Handle timeout_LID */
528 itemid.num = offset_timeout_LID->lid;
529 itemid.type = VCDINFO_ITEM_TYPE_LID;
530 dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
531 vcdplayer_play( p_access, itemid );
534 int num_selections = vcdinf_get_num_selections(p_vcd->pxd.psd);
535 if (num_selections > 0) {
536 /* Pick a random selection. */
537 unsigned int bsn=vcdinf_get_bsn(p_vcd->pxd.psd);
538 int rand_selection=bsn +
539 (int) ((num_selections+0.0)*rand()/(RAND_MAX+1.0));
540 lid_t rand_lid=vcdinfo_selection_get_lid (p_vcd->vcd,
543 itemid.num = rand_lid;
544 itemid.type = VCDINFO_ITEM_TYPE_LID;
545 dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
546 rand_selection - bsn, rand_lid);
547 vcdplayer_play( p_access, itemid );
549 } else if (p_vcd->in_still) {
550 /* Hack: Just go back and do still again */
552 return READ_STILL_FRAME;
557 case VCDINFO_ITEM_TYPE_NOTFOUND:
558 LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
560 case VCDINFO_ITEM_TYPE_SPAREID2:
561 LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
563 case VCDINFO_ITEM_TYPE_LID:
564 LOG_ERR( "LID in PBC -- not supposed to happen" );
570 /* FIXME: Should handle autowait ... */
576 Read block into p_buf and return the status back.
578 This routine is a bit complicated because on reaching the end of
579 a track or entry we may automatically advance to the item, or
580 interpret the next item in the playback-control list.
582 vcdplayer_read_status_t
583 vcdplayer_read (access_t * p_access, uint8_t *p_buf)
586 /* p_access->handle_events (); */
589 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
590 if ( p_vcd->i_lsn > p_vcd->end_lsn ) {
591 vcdplayer_read_status_t read_status;
593 /* We've run off of the end of this entry. Do we continue or stop? */
594 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
595 "end reached, cur: %u, end: %u\n", p_vcd->i_lsn, p_vcd->end_lsn);
597 handle_item_continuation:
598 read_status = vcdplayer_pbc_is_on( p_vcd )
599 ? vcdplayer_pbc_nav( p_access, &wait_time )
600 : vcdplayer_non_pbc_nav( p_access, &wait_time );
602 if (READ_STILL_FRAME == read_status) {
604 return READ_STILL_FRAME;
607 if (READ_BLOCK != read_status) return read_status;
610 /* Read the next block.
612 Important note: we probably speed things up by removing "data"
613 and the memcpy to it by extending vcd_image_source_read_mode2
614 to allow a mode to do what's below in addition to its
615 "raw" and "block" mode. It also would probably improve the modularity
616 a little bit as well.
620 CdIo *p_img = vcdinfo_get_cd_image(p_vcd->vcd);
622 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
623 uint8_t data [M2F2_SECTOR_SIZE];
626 vcdsector_t vcd_sector;
629 if (cdio_read_mode2_sector(p_img, &vcd_sector, p_vcd->i_lsn, true)!=0) {
630 dbg_print(INPUT_DBG_LSN, "read error\n");
636 if ( p_vcd->i_lsn >= p_vcd->end_lsn ) {
637 /* We've run off of the end of p_vcd entry. Do we continue or stop? */
638 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
639 "end reached in reading, cur: %u, end: %u\n",
640 p_vcd->i_lsn, p_vcd->end_lsn);
644 /* Check header ID for a padding sector and simply discard
645 these. It is alleged that VCD's put these in to keep the
648 } while((vcd_sector.subheader[2]&~0x01)==0x60);
650 if ( p_vcd->i_lsn >= p_vcd->end_lsn )
651 /* We've run off of the end of this entry. Do we continue or stop? */
652 goto handle_item_continuation;
654 memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE);
660 Get the next play-item in the list given in the LIDs. Note play-item
661 here refers to list of play-items for a single LID It shouldn't be
662 confused with a user's list of favorite things to play or the
663 "next" field of a LID which moves us to a different LID.
666 vcdplayer_inc_play_item( access_t *p_access )
668 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
672 dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcd->pdi);
674 if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return false;
676 noi = vcdinf_pld_get_noi(p_vcd->pxd.pld);
678 if ( noi <= 0 ) return false;
680 /* Handle delays like autowait or wait here? */
684 if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return false;
687 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld,
689 vcdinfo_itemid_t trans_itemid;
691 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
693 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
694 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
695 p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num));
696 vcdplayer_play( p_access, trans_itemid );
702 Play item assocated with the "default" selection.
704 Return false if there was some problem.
707 vcdplayer_play_default( access_t * p_access )
709 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
711 vcdinfo_itemid_t itemid;
714 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
720 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
721 "current: %d" , p_vcd->play_item.num);
723 itemid.type = p_vcd->play_item.type;
725 if (vcdplayer_pbc_is_on(p_vcd)) {
727 #if defined(LIBVCD_VERSION)
728 lid_t lid=vcdinfo_get_multi_default_lid(p_vcd->vcd, p_vcd->i_lid,
731 if (VCDINFO_INVALID_LID != lid) {
733 itemid.type = VCDINFO_ITEM_TYPE_LID;
734 dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num);
736 dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcd->i_lid);
740 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), p_vcd->i_lid);
742 switch (p_vcd->pxd.descriptor_type) {
743 case PSD_TYPE_SELECTION_LIST:
744 case PSD_TYPE_EXT_SELECTION_LIST:
745 if (p_vcd->pxd.psd == NULL) return false;
746 vcdplayer_update_entry( p_access,
747 vcdinfo_get_default_offset(p_vcd->vcd,
749 &itemid.num, "default");
752 case PSD_TYPE_PLAY_LIST:
753 case PSD_TYPE_END_LIST:
754 case PSD_TYPE_COMMAND_LIST:
755 LOG_WARN( "There is no PBC 'default' selection here" );
758 #endif /* LIBVCD_VERSION (< 0.7.21) */
763 /* PBC is not on. "default" selection beginning of current
766 p_vcd->play_item.num = p_vcd->play_item.num;
770 /** ??? p_vcd->update_title(); ***/
771 vcdplayer_play( p_access, itemid );
777 Play item assocated with the "next" selection.
779 Return false if there was some problem.
782 vcdplayer_play_next( access_t * p_access )
784 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
786 vcdinfo_obj_t *p_obj;
787 vcdinfo_itemid_t itemid;
789 if (!p_vcd) return false;
791 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
792 "current: %d" , p_vcd->play_item.num);
796 itemid.type = p_vcd->play_item.type;
798 if (vcdplayer_pbc_is_on(p_vcd)) {
800 vcdinfo_lid_get_pxd(p_obj, &(p_vcd->pxd), p_vcd->i_lid);
802 switch (p_vcd->pxd.descriptor_type) {
803 case PSD_TYPE_SELECTION_LIST:
804 case PSD_TYPE_EXT_SELECTION_LIST:
805 if (p_vcd->pxd.psd == NULL) return false;
806 vcdplayer_update_entry( p_access,
807 vcdinf_psd_get_next_offset(p_vcd->pxd.psd),
808 &itemid.num, "next");
809 itemid.type = VCDINFO_ITEM_TYPE_LID;
812 case PSD_TYPE_PLAY_LIST:
813 if (p_vcd->pxd.pld == NULL) return false;
814 vcdplayer_update_entry( p_access,
815 vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
816 &itemid.num, "next");
817 itemid.type = VCDINFO_ITEM_TYPE_LID;
820 case PSD_TYPE_END_LIST:
821 case PSD_TYPE_COMMAND_LIST:
822 LOG_WARN( "There is no PBC 'next' selection here" );
827 /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
831 switch (p_vcd->play_item.type) {
832 case VCDINFO_ITEM_TYPE_ENTRY:
833 case VCDINFO_ITEM_TYPE_SEGMENT:
834 case VCDINFO_ITEM_TYPE_TRACK:
836 switch (p_vcd->play_item.type) {
837 case VCDINFO_ITEM_TYPE_ENTRY:
838 max_entry = p_vcd->i_entries;
840 case VCDINFO_ITEM_TYPE_SEGMENT:
841 max_entry = p_vcd->i_segments;
843 case VCDINFO_ITEM_TYPE_TRACK:
844 max_entry = p_vcd->i_tracks;
846 default: ; /* Handle exceptional cases below */
849 if (p_vcd->play_item.num+1 < max_entry) {
850 itemid.num = p_vcd->play_item.num+1;
852 LOG_WARN( "At the end - non-PBC 'next' not possible here" );
858 case VCDINFO_ITEM_TYPE_LID:
860 /* Should have handled above. */
861 LOG_WARN( "Internal inconsistency - should not have gotten here." );
869 /** ??? p_vcd->update_title(); ***/
870 vcdplayer_play( p_access, itemid );
876 Play item assocated with the "prev" selection.
878 Return false if there was some problem.
881 vcdplayer_play_prev( access_t * p_access )
883 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
884 vcdinfo_obj_t *p_obj = p_vcd->vcd;
885 vcdinfo_itemid_t itemid;
887 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
888 "current: %d" , p_vcd->play_item.num);
890 itemid.type = p_vcd->play_item.type;
892 if (vcdplayer_pbc_is_on(p_vcd)) {
894 vcdinfo_lid_get_pxd(p_obj, &(p_vcd->pxd), p_vcd->i_lid);
896 switch (p_vcd->pxd.descriptor_type) {
897 case PSD_TYPE_SELECTION_LIST:
898 case PSD_TYPE_EXT_SELECTION_LIST:
899 if (p_vcd->pxd.psd == NULL) return false;
900 vcdplayer_update_entry( p_access,
901 vcdinf_psd_get_prev_offset(p_vcd->pxd.psd),
902 &itemid.num, "prev");
903 itemid.type = VCDINFO_ITEM_TYPE_LID;
906 case PSD_TYPE_PLAY_LIST:
907 if (p_vcd->pxd.pld == NULL) return false;
908 vcdplayer_update_entry( p_access,
909 vcdinf_pld_get_prev_offset(p_vcd->pxd.pld),
910 &itemid.num, "prev");
911 itemid.type = VCDINFO_ITEM_TYPE_LID;
914 case PSD_TYPE_END_LIST:
915 case PSD_TYPE_COMMAND_LIST:
916 LOG_WARN( "There is no PBC 'prev' selection here" );
921 /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
923 int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type)
926 if (p_vcd->play_item.num > min_entry) {
927 itemid.num = p_vcd->play_item.num-1;
929 LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
935 /** ??? p_vcd->update_title(); ***/
936 vcdplayer_play( p_access, itemid );
942 Play item assocated with the "return" selection.
944 Return false if there was some problem.
947 vcdplayer_play_return( access_t * p_access )
949 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
950 vcdinfo_obj_t *p_obj = p_vcd->vcd;
951 vcdinfo_itemid_t itemid;
953 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
954 "current: %d" , p_vcd->play_item.num);
956 itemid.type = p_vcd->play_item.type;
958 if (vcdplayer_pbc_is_on(p_vcd)) {
960 vcdinfo_lid_get_pxd(p_obj, &(p_vcd->pxd), p_vcd->i_lid);
962 switch (p_vcd->pxd.descriptor_type) {
963 case PSD_TYPE_SELECTION_LIST:
964 case PSD_TYPE_EXT_SELECTION_LIST:
965 if (p_vcd->pxd.psd == NULL) return false;
966 vcdplayer_update_entry( p_access,
967 vcdinf_psd_get_return_offset(p_vcd->pxd.psd),
968 &itemid.num, "return");
969 itemid.type = VCDINFO_ITEM_TYPE_LID;
972 case PSD_TYPE_PLAY_LIST:
973 if (p_vcd->pxd.pld == NULL) return false;
974 vcdplayer_update_entry( p_access,
975 vcdinf_pld_get_return_offset(p_vcd->pxd.pld),
976 &itemid.num, "return");
977 itemid.type = VCDINFO_ITEM_TYPE_LID;
980 case PSD_TYPE_END_LIST:
981 case PSD_TYPE_COMMAND_LIST:
982 LOG_WARN( "There is no PBC 'return' selection here" );
987 /* PBC is not on. "Return" selection is min_entry if possible. */
989 p_vcd->play_item.num = (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type)
994 /** ??? p_vcd->update_title(); ***/
995 vcdplayer_play( p_access, itemid );