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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, 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 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_input.h>
38 #include <vlc_interface.h>
41 #include "vcdplayer.h"
44 #include <cdio/cdio.h>
45 #include <cdio/util.h>
46 #include <libvcd/info.h>
49 Return true if playback control (PBC) is on
52 vcdplayer_pbc_is_on( const vcdplayer_t *p_vcdplayer )
54 return VCDINFO_INVALID_ENTRY != p_vcdplayer->i_lid;
57 /* Given an itemid, return the size for the object (via information
58 previously stored when opening the vcd). */
60 vcdplayer_get_item_size(access_t * p_access, vcdinfo_itemid_t itemid)
62 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
64 switch (itemid.type) {
65 case VCDINFO_ITEM_TYPE_ENTRY:
66 return p_vcdplayer->entry[itemid.num].size;
68 case VCDINFO_ITEM_TYPE_SEGMENT:
69 return p_vcdplayer->segment[itemid.num].size;
71 case VCDINFO_ITEM_TYPE_TRACK:
72 return p_vcdplayer->track[itemid.num-1].size;
74 case VCDINFO_ITEM_TYPE_LID:
75 /* Play list number (LID) */
78 case VCDINFO_ITEM_TYPE_NOTFOUND:
79 case VCDINFO_ITEM_TYPE_SPAREID2:
81 LOG_ERR("%s %d", "bad item type", itemid.type);
87 vcdplayer_update_entry( access_t * p_access, uint16_t ofs,
88 uint16_t *entry, const char *label)
90 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
92 if ( ofs == VCDINFO_INVALID_OFFSET ) {
93 *entry = VCDINFO_INVALID_ENTRY;
95 vcdinfo_offset_t *off = vcdinfo_get_offset_t(p_vcdplayer->vcd, ofs);
98 dbg_print(INPUT_DBG_PBC, "%s: LID %d", label, off->lid);
100 *entry = VCDINFO_INVALID_ENTRY;
104 /* Handles navigation when NOT in PBC reaching the end of a play item.
106 The navigations rules here may be sort of made up, but the intent
107 is to do something that's probably right or helpful.
109 return true if the caller should return.
111 static vcdplayer_read_status_t
112 vcdplayer_non_pbc_nav ( access_t *p_access, uint8_t *wait_time )
114 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
116 /* Not in playback control. Do we advance automatically or stop? */
117 switch (p_vcdplayer->play_item.type) {
118 case VCDINFO_ITEM_TYPE_TRACK:
119 case VCDINFO_ITEM_TYPE_ENTRY: {
120 if ( ! vcdplayer_play_next( p_access ) )
124 case VCDINFO_ITEM_TYPE_SPAREID2:
125 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
127 if (p_vcdplayer->in_still)
129 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
130 "End of still spareid2" );
132 return READ_STILL_FRAME ;
135 case VCDINFO_ITEM_TYPE_NOTFOUND:
136 LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen");
138 case VCDINFO_ITEM_TYPE_LID:
139 LOG_ERR ("LID outside PBC -- not supposed to happen");
141 case VCDINFO_ITEM_TYPE_SEGMENT:
142 /* Hack: Just go back and do still again */
144 if (p_vcdplayer->in_still)
146 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
147 "End of still Segment" );
149 return READ_STILL_FRAME;
157 Set reading to play an entire track.
160 _vcdplayer_set_track(access_t * p_access, track_t i_track)
162 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
163 if (i_track < 1 || i_track > p_vcdplayer->i_tracks)
166 const vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
167 vcdinfo_itemid_t itemid;
169 itemid.num = i_track;
170 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
171 p_vcdplayer->in_still = 0;
173 VCDSetOrigin(p_access, vcdinfo_get_track_lsn(p_vcdinfo, i_track),
176 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
181 Set reading to play an entry
184 _vcdplayer_set_entry(access_t * p_access, unsigned int num)
186 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
187 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
188 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
190 if (num >= i_entries) {
191 LOG_ERR("%s %d", "bad entry number", num);
194 vcdinfo_itemid_t itemid;
197 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
198 p_vcdplayer->i_still = 0;
200 VCDSetOrigin(p_access, vcdinfo_get_entry_lsn(p_vcdinfo, num),
201 vcdinfo_get_track(p_vcdinfo, num), &itemid);
203 dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u",
204 p_vcdplayer->i_lsn, p_vcdplayer->track_end_lsn);
209 Set reading to play an segment (e.g. still frame)
212 _vcdplayer_set_segment(access_t * p_access, unsigned int num)
214 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
215 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
216 segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
219 LOG_ERR("%s %d", "bad segment number", num);
222 vcdinfo_itemid_t itemid;
224 if (VCDINFO_NULL_LSN==p_vcdplayer->i_lsn) {
226 "Error in getting current segment number", num);
231 itemid.type = VCDINFO_ITEM_TYPE_SEGMENT;
233 VCDSetOrigin(p_access, vcdinfo_get_seg_lsn(p_vcdinfo, num), 0, &itemid);
235 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
240 /* Play a single item. */
242 vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
244 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
245 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
247 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d, itemid.type: %d",
248 itemid.num, itemid.type);
250 p_vcdplayer->i_still = 0;
252 switch (itemid.type) {
253 case VCDINFO_ITEM_TYPE_SEGMENT:
255 vcdinfo_video_segment_type_t segtype
256 = vcdinfo_get_video_type(p_vcdinfo, itemid.num);
257 segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
259 dbg_print(INPUT_DBG_PBC, "%s (%d), itemid.num: %d",
260 vcdinfo_video_type2str(p_vcdinfo, itemid.num),
261 (int) segtype, itemid.num);
263 if (itemid.num >= i_segs) return false;
264 _vcdplayer_set_segment(p_access, itemid.num);
268 case VCDINFO_FILES_VIDEO_NTSC_STILL:
269 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
270 case VCDINFO_FILES_VIDEO_PAL_STILL:
271 case VCDINFO_FILES_VIDEO_PAL_STILL2:
272 p_vcdplayer->i_still = STILL_READING;
275 p_vcdplayer->i_still = 0;
281 case VCDINFO_ITEM_TYPE_TRACK:
282 dbg_print(INPUT_DBG_PBC, "track %d", itemid.num);
283 if (itemid.num < 1 || itemid.num > p_vcdplayer->i_tracks) return false;
284 _vcdplayer_set_track(p_access, itemid.num);
287 case VCDINFO_ITEM_TYPE_ENTRY:
289 unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
290 dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num);
291 if (itemid.num >= i_entries) return false;
292 _vcdplayer_set_entry(p_access, itemid.num);
296 case VCDINFO_ITEM_TYPE_LID:
297 LOG_ERR("%s", "Should have converted p_vcdplayer above");
301 case VCDINFO_ITEM_TYPE_NOTFOUND:
302 dbg_print(INPUT_DBG_PBC, "play nothing");
303 p_vcdplayer->i_lsn = p_vcdplayer->end_lsn;
307 LOG_ERR("item type %d not implemented.", itemid.type);
311 p_vcdplayer->play_item = itemid;
313 /* Some players like xine, have a fifo queue of audio and video buffers
314 that need to be flushed when playing a new selection. */
315 /* if (p_vcdplayer->flush_buffers)
316 p_vcdplayer->flush_buffers(); */
321 Set's start origin and size for subsequent seeks.
322 input: p_vcdplayer->i_lsn, p_vcdplayer->play_item
323 changed: p_vcdplayer->origin_lsn, p_vcdplayer->end_lsn
327 vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track,
328 const vcdinfo_itemid_t *p_itemid)
330 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
331 const size_t i_size= vcdplayer_get_item_size(p_access, *p_itemid);
333 if( VCDINFO_NULL_LSN == i_lsn )
335 LOG_ERR("%s %d", "Invalid LSN for track", i_track);
339 p_vcdplayer->play_item.num = p_itemid->num;
340 p_vcdplayer->play_item.type = p_itemid->type;
341 p_vcdplayer->i_lsn = i_lsn;
342 p_vcdplayer->end_lsn = p_vcdplayer->i_lsn + i_size;
343 p_vcdplayer->origin_lsn = p_vcdplayer->i_lsn;
344 p_vcdplayer->i_track = i_track;
345 p_vcdplayer->track_lsn = vcdinfo_get_track_lsn(p_vcdplayer->vcd,
347 p_vcdplayer->track_end_lsn = p_vcdplayer->track_lsn +
348 vcdinfo_get_track_sect_count(p_vcdplayer->vcd, i_track);
350 dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN),
351 "lsn %u, end LSN: %u item.num %d, item.type %d",
352 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn,
353 p_vcdplayer->play_item.num, p_vcdplayer->play_item.type);
357 Get the next play-item in the list given in the LIDs. Note play-item
358 here refers to list of play-items for a single LID It shouldn't be
359 confused with a user's list of favorite things to play or the
360 "next" field of a LID which moves us to a different LID.
363 vcdplayer_inc_play_item(access_t *p_access)
365 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
368 dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcdplayer->pdi);
370 if ( NULL == p_vcdplayer || NULL == p_vcdplayer->pxd.pld )
373 noi = vcdinf_pld_get_noi(p_vcdplayer->pxd.pld);
377 /* Handle delays like autowait or wait here? */
381 if ( p_vcdplayer->pdi < 0 || p_vcdplayer->pdi >= noi )
384 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcdplayer->pxd.pld,
386 vcdinfo_itemid_t trans_itemid;
388 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
390 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
391 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
392 p_vcdplayer->pdi, vcdinfo_pin2str (trans_itemid_num));
393 return vcdplayer_play_single_item(p_access, trans_itemid);
397 vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid)
399 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
401 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d itemid.type: %d",
402 itemid.num, itemid.type);
404 if (!vcdplayer_pbc_is_on(p_vcdplayer)) {
405 vcdplayer_play_single_item(p_access, itemid);
407 /* PBC on - Itemid.num is LID. */
409 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
411 if (p_vcdinfo == NULL)
414 p_vcdplayer->i_lid = itemid.num;
415 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), itemid.num);
417 switch (p_vcdplayer->pxd.descriptor_type) {
419 case PSD_TYPE_SELECTION_LIST:
420 case PSD_TYPE_EXT_SELECTION_LIST: {
421 vcdinfo_itemid_t trans_itemid;
422 uint16_t trans_itemid_num;
424 if (p_vcdplayer->pxd.psd == NULL) return;
425 trans_itemid_num = vcdinf_psd_get_itemid(p_vcdplayer->pxd.psd);
426 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
427 p_vcdplayer->i_loop = 1;
428 p_vcdplayer->loop_item = trans_itemid;
429 vcdplayer_play_single_item(p_access, trans_itemid);
433 case PSD_TYPE_PLAY_LIST: {
434 if (p_vcdplayer->pxd.pld == NULL) return;
435 p_vcdplayer->pdi = -1;
436 vcdplayer_inc_play_item(p_access);
440 case PSD_TYPE_END_LIST:
441 case PSD_TYPE_COMMAND_LIST:
449 /* Handles PBC navigation when reaching the end of a play item. */
450 static vcdplayer_read_status_t
451 vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time )
453 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
455 /* We are in playback control. */
456 vcdinfo_itemid_t itemid;
458 /* The end of an entry is really the end of the associated
459 sequence (or track). */
461 if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) &&
462 (p_vcdplayer->i_lsn < p_vcdplayer->end_lsn) ) {
463 /* Set up to just continue to the next entry */
464 p_vcdplayer->play_item.num++;
465 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
466 "continuing into next entry: %u", p_vcdplayer->play_item.num);
467 vcdplayer_play_single_item( p_access, p_vcdplayer->play_item );
468 /* p_vcdplayer->update_title(); */
472 switch (p_vcdplayer->pxd.descriptor_type) {
473 case PSD_TYPE_END_LIST:
476 case PSD_TYPE_PLAY_LIST: {
477 if (vcdplayer_inc_play_item(p_access))
480 /* Set up for caller process wait time given. */
481 if (p_vcdplayer->i_still) {
482 *wait_time = vcdinf_get_wait_time(p_vcdplayer->pxd.pld);
483 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
484 "playlist wait time: %d", *wait_time);
485 return READ_STILL_FRAME;
488 /* Wait time has been processed; continue with next entry. */
489 vcdplayer_update_entry( p_access,
490 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
491 &itemid.num, "next" );
492 itemid.type = VCDINFO_ITEM_TYPE_LID;
493 vcdplayer_play( p_access, itemid );
496 case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
497 case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
499 uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcdplayer->pxd.psd);
500 uint16_t max_loop = vcdinf_get_loop_count(p_vcdplayer->pxd.psd);
501 vcdinfo_offset_t *offset_timeout_LID =
502 vcdinfo_get_offset_t(p_vcdplayer->vcd, timeout_offs);
504 dbg_print(INPUT_DBG_PBC, "looped: %d, max_loop %d",
505 p_vcdplayer->i_loop, max_loop);
507 /* Set up for caller process wait time given. */
508 if (p_vcdplayer->i_still) {
509 *wait_time = vcdinf_get_timeout_time(p_vcdplayer->pxd.psd);
510 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
511 "playlist wait_time: %d", *wait_time);
512 return READ_STILL_FRAME;
515 /* Wait time has been processed; continue with next entry. */
516 /* Handle any looping given. */
517 if ( max_loop == 0 || p_vcdplayer->i_loop < max_loop ) {
518 p_vcdplayer->i_loop++;
519 if (p_vcdplayer->i_loop == 0x7f) p_vcdplayer->i_loop = 0;
520 vcdplayer_play_single_item(p_access, p_vcdplayer->loop_item);
521 /* if (p_vcdplayer->i_still) p_vcdplayer->force_redisplay();*/
525 /* Looping finished and wait finished. Move to timeout
526 entry or next entry, or handle still. */
528 if (NULL != offset_timeout_LID) {
529 /* Handle timeout_LID */
530 itemid.num = offset_timeout_LID->lid;
531 itemid.type = VCDINFO_ITEM_TYPE_LID;
532 dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
533 vcdplayer_play( p_access, itemid );
536 int i_selections = vcdinf_get_num_selections(p_vcdplayer->pxd.psd);
537 if (i_selections > 0) {
538 /* Pick a random selection. */
539 unsigned int bsn=vcdinf_get_bsn(p_vcdplayer->pxd.psd);
540 int rand_selection=bsn +
541 (int) ((i_selections+0.0)*rand()/(RAND_MAX+1.0));
542 lid_t rand_lid=vcdinfo_selection_get_lid (p_vcdplayer->vcd,
545 itemid.num = rand_lid;
546 itemid.type = VCDINFO_ITEM_TYPE_LID;
547 dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
548 rand_selection - bsn, rand_lid);
549 vcdplayer_play( p_access, itemid );
551 } else if (p_vcdplayer->i_still) {
552 /* Hack: Just go back and do still again */
554 return READ_STILL_FRAME;
559 case VCDINFO_ITEM_TYPE_NOTFOUND:
560 LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
562 case VCDINFO_ITEM_TYPE_SPAREID2:
563 LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
565 case VCDINFO_ITEM_TYPE_LID:
566 LOG_ERR( "LID in PBC -- not supposed to happen" );
572 /* FIXME: Should handle autowait ... */
578 Read block into p_buf and return the status back.
580 This routine is a bit complicated because on reaching the end of
581 a track or entry we may automatically advance to the item, or
582 interpret the next item in the playback-control list.
584 vcdplayer_read_status_t
585 vcdplayer_read (access_t * p_access, uint8_t *p_buf)
588 /* p_access->handle_events (); */
591 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
592 if ( p_vcdplayer->i_lsn > p_vcdplayer->end_lsn ) {
593 vcdplayer_read_status_t read_status;
595 /* We've run off of the end of this entry. Do we continue or stop? */
596 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
597 "end reached, cur: %u, end: %u\n",
598 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
600 handle_item_continuation:
601 read_status = vcdplayer_pbc_is_on( p_vcdplayer )
602 ? vcdplayer_pbc_nav( p_access, &wait_time )
603 : vcdplayer_non_pbc_nav( p_access, &wait_time );
605 if (READ_STILL_FRAME == read_status) {
607 return READ_STILL_FRAME;
610 if (READ_BLOCK != read_status) return read_status;
613 /* Read the next block.
615 Important note: we probably speed things up by removing "data"
616 and the memcpy to it by extending vcd_image_source_read_mode2
617 to allow a mode to do what's below in addition to its
618 "raw" and "block" mode. It also would probably improve the modularity
619 a little bit as well.
623 CdIo *p_img = vcdinfo_get_cd_image(p_vcdplayer->vcd);
625 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
626 uint8_t data [M2F2_SECTOR_SIZE];
629 vcdsector_t vcd_sector;
632 if (cdio_read_mode2_sector(p_img, &vcd_sector,
633 p_vcdplayer->i_lsn, true)!=0) {
634 dbg_print(INPUT_DBG_LSN, "read error\n");
635 p_vcdplayer->i_lsn++;
638 p_vcdplayer->i_lsn++;
640 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) {
641 /* We've run off of the end of this entry. Do we continue or stop? */
642 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
643 "end reached in reading, cur: %u, end: %u\n",
644 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
648 /* Check header ID for a padding sector and simply discard
649 these. It is alleged that VCD's put these in to keep the
652 } while((vcd_sector.subheader[2]&~0x01)==0x60);
654 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn )
655 /* We've run off of the end of this entry. Do we continue or stop? */
656 goto handle_item_continuation;
658 memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE);
664 Play item assocated with the "default" selection.
666 Return false if there was some problem.
669 vcdplayer_play_default( access_t * p_access )
671 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
673 vcdinfo_itemid_t itemid;
676 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
677 "null p_vcdplayer" );
682 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
683 "current: %d" , p_vcdplayer->play_item.num);
685 itemid.type = p_vcdplayer->play_item.type;
687 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
689 #if defined(LIBVCD_VERSION)
690 lid_t lid=vcdinfo_get_multi_default_lid(p_vcdplayer->vcd, p_vcdplayer->i_lid,
693 if (VCDINFO_INVALID_LID != lid) {
695 itemid.type = VCDINFO_ITEM_TYPE_LID;
696 dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num);
698 dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcdplayer->i_lid);
703 vcdinfo_lid_get_pxd(p_vcdplayer->vcd, &(p_vcdplayer->pxd),
706 switch (p_vcdplayer->pxd.descriptor_type) {
707 case PSD_TYPE_SELECTION_LIST:
708 case PSD_TYPE_EXT_SELECTION_LIST:
709 if (p_vcdplayer->pxd.psd == NULL) return false;
710 vcdplayer_update_entry(p_access,
711 vcdinfo_get_default_offset(p_vcdplayer->vcd,
713 &itemid.num, "default");
716 case PSD_TYPE_PLAY_LIST:
717 case PSD_TYPE_END_LIST:
718 case PSD_TYPE_COMMAND_LIST:
719 LOG_WARN( "There is no PBC 'default' selection here" );
722 #endif /* LIBVCD_VERSION (< 0.7.21) */
727 /* PBC is not on. "default" selection beginning of current
730 itemid.num = p_vcdplayer->play_item.num;
734 /** ??? p_vcdplayer->update_title(); ***/
735 vcdplayer_play( p_access, itemid );
741 Play item assocated with the "next" selection.
743 Return false if there was some problem.
746 vcdplayer_play_next( access_t * p_access )
748 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
750 vcdinfo_obj_t *p_vcdinfo;
751 vcdinfo_itemid_t itemid;
753 if (!p_vcdplayer) return false;
755 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
756 "current: %d" , p_vcdplayer->play_item.num);
758 p_vcdinfo = p_vcdplayer->vcd;
760 itemid = p_vcdplayer->play_item;
762 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
764 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
766 switch (p_vcdplayer->pxd.descriptor_type) {
767 case PSD_TYPE_SELECTION_LIST:
768 case PSD_TYPE_EXT_SELECTION_LIST:
769 if (p_vcdplayer->pxd.psd == NULL) return false;
770 vcdplayer_update_entry(p_access,
771 vcdinf_psd_get_next_offset(p_vcdplayer->pxd.psd),
772 &itemid.num, "next");
773 itemid.type = VCDINFO_ITEM_TYPE_LID;
776 case PSD_TYPE_PLAY_LIST:
777 if (p_vcdplayer->pxd.pld == NULL) return false;
778 vcdplayer_update_entry(p_access,
779 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
780 &itemid.num, "next");
781 itemid.type = VCDINFO_ITEM_TYPE_LID;
784 case PSD_TYPE_END_LIST:
785 case PSD_TYPE_COMMAND_LIST:
786 LOG_WARN( "There is no PBC 'next' selection here" );
791 /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
795 switch (p_vcdplayer->play_item.type) {
796 case VCDINFO_ITEM_TYPE_ENTRY:
797 case VCDINFO_ITEM_TYPE_SEGMENT:
798 case VCDINFO_ITEM_TYPE_TRACK:
800 switch (p_vcdplayer->play_item.type) {
801 case VCDINFO_ITEM_TYPE_ENTRY:
802 max_entry = p_vcdplayer->i_entries;
804 case VCDINFO_ITEM_TYPE_SEGMENT:
805 max_entry = p_vcdplayer->i_segments;
807 case VCDINFO_ITEM_TYPE_TRACK:
808 max_entry = p_vcdplayer->i_tracks;
810 default: ; /* Handle exceptional cases below */
813 if (p_vcdplayer->play_item.num+1 < max_entry) {
814 itemid.num = p_vcdplayer->play_item.num+1;
816 LOG_WARN( "At the end - non-PBC 'next' not possible here" );
822 case VCDINFO_ITEM_TYPE_LID:
823 /* Should have handled above. */
824 LOG_WARN( "Internal inconsistency - should not have gotten here." );
831 /** ??? p_vcdplayer->update_title(); ***/
832 vcdplayer_play( p_access, itemid );
838 Play item assocated with the "prev" selection.
840 Return false if there was some problem.
843 vcdplayer_play_prev( access_t * p_access )
845 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
846 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
847 vcdinfo_itemid_t itemid;
849 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
850 "current: %d" , p_vcdplayer->play_item.num);
852 itemid = p_vcdplayer->play_item;
854 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
856 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
858 switch (p_vcdplayer->pxd.descriptor_type) {
859 case PSD_TYPE_SELECTION_LIST:
860 case PSD_TYPE_EXT_SELECTION_LIST:
861 if (p_vcdplayer->pxd.psd == NULL) return false;
862 vcdplayer_update_entry(p_access,
863 vcdinf_psd_get_prev_offset(p_vcdplayer->pxd.psd),
864 &itemid.num, "prev");
865 itemid.type = VCDINFO_ITEM_TYPE_LID;
868 case PSD_TYPE_PLAY_LIST:
869 if (p_vcdplayer->pxd.pld == NULL) return false;
870 vcdplayer_update_entry(p_access,
871 vcdinf_pld_get_prev_offset(p_vcdplayer->pxd.pld),
872 &itemid.num, "prev");
873 itemid.type = VCDINFO_ITEM_TYPE_LID;
876 case PSD_TYPE_END_LIST:
877 case PSD_TYPE_COMMAND_LIST:
878 LOG_WARN( "There is no PBC 'prev' selection here" );
883 /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
885 int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
888 if (p_vcdplayer->play_item.num > min_entry) {
889 itemid.num = p_vcdplayer->play_item.num-1;
891 LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
897 /** ??? p_vcdplayer->update_title(); ***/
898 vcdplayer_play( p_access, itemid );
904 Play item assocated with the "return" selection.
906 Return false if there was some problem.
909 vcdplayer_play_return( access_t * p_access )
911 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
912 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
913 vcdinfo_itemid_t itemid;
915 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
916 "current: %d" , p_vcdplayer->play_item.num);
918 itemid = p_vcdplayer->play_item;
920 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
922 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
924 switch (p_vcdplayer->pxd.descriptor_type) {
925 case PSD_TYPE_SELECTION_LIST:
926 case PSD_TYPE_EXT_SELECTION_LIST:
927 if (p_vcdplayer->pxd.psd == NULL) return false;
928 vcdplayer_update_entry(p_access,
929 vcdinf_psd_get_return_offset(p_vcdplayer->pxd.psd),
930 &itemid.num, "return");
931 itemid.type = VCDINFO_ITEM_TYPE_LID;
934 case PSD_TYPE_PLAY_LIST:
935 if (p_vcdplayer->pxd.pld == NULL) return false;
936 vcdplayer_update_entry(p_access,
937 vcdinf_pld_get_return_offset(p_vcdplayer->pxd.pld),
938 &itemid.num, "return");
939 itemid.type = VCDINFO_ITEM_TYPE_LID;
942 case PSD_TYPE_END_LIST:
943 case PSD_TYPE_COMMAND_LIST:
944 LOG_WARN( "There is no PBC 'return' selection here" );
949 /* PBC is not on. "Return" selection is min_entry if possible. */
951 p_vcdplayer->play_item.num =
952 (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
957 /** ??? p_vcdplayer->update_title(); ***/
958 vcdplayer_play( p_access, itemid );