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>
42 #include "vcdplayer.h"
45 #include <cdio/cdio.h>
46 #include <cdio/util.h>
47 #include <libvcd/info.h>
50 Return true if playback control (PBC) is on
53 vcdplayer_pbc_is_on( const vcdplayer_t *p_vcdplayer )
55 return VCDINFO_INVALID_ENTRY != p_vcdplayer->i_lid;
58 /* Given an itemid, return the size for the object (via information
59 previously stored when opening the vcd). */
61 vcdplayer_get_item_size(access_t * p_access, vcdinfo_itemid_t itemid)
63 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
65 switch (itemid.type) {
66 case VCDINFO_ITEM_TYPE_ENTRY:
67 return p_vcdplayer->entry[itemid.num].size;
69 case VCDINFO_ITEM_TYPE_SEGMENT:
70 return p_vcdplayer->segment[itemid.num].size;
72 case VCDINFO_ITEM_TYPE_TRACK:
73 return p_vcdplayer->track[itemid.num-1].size;
75 case VCDINFO_ITEM_TYPE_LID:
76 /* Play list number (LID) */
79 case VCDINFO_ITEM_TYPE_NOTFOUND:
80 case VCDINFO_ITEM_TYPE_SPAREID2:
82 LOG_ERR("%s %d", "bad item type", itemid.type);
88 vcdplayer_update_entry( access_t * p_access, uint16_t ofs,
89 uint16_t *entry, const char *label)
91 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
93 if ( ofs == VCDINFO_INVALID_OFFSET ) {
94 *entry = VCDINFO_INVALID_ENTRY;
96 vcdinfo_offset_t *off = vcdinfo_get_offset_t(p_vcdplayer->vcd, ofs);
99 dbg_print(INPUT_DBG_PBC, "%s: LID %d", label, off->lid);
101 *entry = VCDINFO_INVALID_ENTRY;
105 /* Handles navigation when NOT in PBC reaching the end of a play item.
107 The navigations rules here may be sort of made up, but the intent
108 is to do something that's probably right or helpful.
110 return true if the caller should return.
112 static vcdplayer_read_status_t
113 vcdplayer_non_pbc_nav ( access_t *p_access, uint8_t *wait_time )
115 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
117 /* Not in playback control. Do we advance automatically or stop? */
118 switch (p_vcdplayer->play_item.type) {
119 case VCDINFO_ITEM_TYPE_TRACK:
120 case VCDINFO_ITEM_TYPE_ENTRY: {
121 if ( ! vcdplayer_play_next( p_access ) )
125 case VCDINFO_ITEM_TYPE_SPAREID2:
126 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
128 if (p_vcdplayer->in_still)
130 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
131 "End of still spareid2" );
133 return READ_STILL_FRAME ;
136 case VCDINFO_ITEM_TYPE_NOTFOUND:
137 LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen");
139 case VCDINFO_ITEM_TYPE_LID:
140 LOG_ERR ("LID outside PBC -- not supposed to happen");
142 case VCDINFO_ITEM_TYPE_SEGMENT:
143 /* Hack: Just go back and do still again */
145 if (p_vcdplayer->in_still)
147 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
148 "End of still Segment" );
150 return READ_STILL_FRAME;
158 Set reading to play an entire track.
161 _vcdplayer_set_track(access_t * p_access, track_t i_track)
163 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
164 if (i_track < 1 || i_track > p_vcdplayer->i_tracks)
167 const vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
168 vcdinfo_itemid_t itemid;
170 itemid.num = i_track;
171 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
172 p_vcdplayer->in_still = 0;
174 VCDSetOrigin(p_access, vcdinfo_get_track_lsn(p_vcdinfo, i_track),
177 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
182 Set reading to play an entry
185 _vcdplayer_set_entry(access_t * p_access, unsigned int num)
187 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
188 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
189 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
191 if (num >= i_entries) {
192 LOG_ERR("%s %d", "bad entry number", num);
195 vcdinfo_itemid_t itemid;
198 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
199 p_vcdplayer->i_still = 0;
201 VCDSetOrigin(p_access, vcdinfo_get_entry_lsn(p_vcdinfo, num),
202 vcdinfo_get_track(p_vcdinfo, num), &itemid);
204 dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u",
205 p_vcdplayer->i_lsn, p_vcdplayer->track_end_lsn);
210 Set reading to play an segment (e.g. still frame)
213 _vcdplayer_set_segment(access_t * p_access, unsigned int num)
215 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
216 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
217 segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
220 LOG_ERR("%s %d", "bad segment number", num);
223 vcdinfo_itemid_t itemid;
225 if (VCDINFO_NULL_LSN==p_vcdplayer->i_lsn) {
227 "Error in getting current segment number", num);
232 itemid.type = VCDINFO_ITEM_TYPE_SEGMENT;
234 VCDSetOrigin(p_access, vcdinfo_get_seg_lsn(p_vcdinfo, num), 0, &itemid);
236 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
241 /* Play a single item. */
243 vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
245 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
246 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
248 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d, itemid.type: %d",
249 itemid.num, itemid.type);
251 p_vcdplayer->i_still = 0;
253 switch (itemid.type) {
254 case VCDINFO_ITEM_TYPE_SEGMENT:
256 vcdinfo_video_segment_type_t segtype
257 = vcdinfo_get_video_type(p_vcdinfo, itemid.num);
258 segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
260 dbg_print(INPUT_DBG_PBC, "%s (%d), itemid.num: %d",
261 vcdinfo_video_type2str(p_vcdinfo, itemid.num),
262 (int) segtype, itemid.num);
264 if (itemid.num >= i_segs) return false;
265 _vcdplayer_set_segment(p_access, itemid.num);
269 case VCDINFO_FILES_VIDEO_NTSC_STILL:
270 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
271 case VCDINFO_FILES_VIDEO_PAL_STILL:
272 case VCDINFO_FILES_VIDEO_PAL_STILL2:
273 p_vcdplayer->i_still = STILL_READING;
276 p_vcdplayer->i_still = 0;
282 case VCDINFO_ITEM_TYPE_TRACK:
283 dbg_print(INPUT_DBG_PBC, "track %d", itemid.num);
284 if (itemid.num < 1 || itemid.num > p_vcdplayer->i_tracks) return false;
285 _vcdplayer_set_track(p_access, itemid.num);
288 case VCDINFO_ITEM_TYPE_ENTRY:
290 unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
291 dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num);
292 if (itemid.num >= i_entries) return false;
293 _vcdplayer_set_entry(p_access, itemid.num);
297 case VCDINFO_ITEM_TYPE_LID:
298 LOG_ERR("%s", "Should have converted p_vcdplayer above");
302 case VCDINFO_ITEM_TYPE_NOTFOUND:
303 dbg_print(INPUT_DBG_PBC, "play nothing");
304 p_vcdplayer->i_lsn = p_vcdplayer->end_lsn;
308 LOG_ERR("item type %d not implemented.", itemid.type);
312 p_vcdplayer->play_item = itemid;
314 /* Some players like xine, have a fifo queue of audio and video buffers
315 that need to be flushed when playing a new selection. */
316 /* if (p_vcdplayer->flush_buffers)
317 p_vcdplayer->flush_buffers(); */
322 Set's start origin and size for subsequent seeks.
323 input: p_vcdplayer->i_lsn, p_vcdplayer->play_item
324 changed: p_vcdplayer->origin_lsn, p_vcdplayer->end_lsn
328 vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track,
329 const vcdinfo_itemid_t *p_itemid)
331 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
332 const size_t i_size= vcdplayer_get_item_size(p_access, *p_itemid);
334 if( VCDINFO_NULL_LSN == i_lsn )
336 LOG_ERR("%s %d", "Invalid LSN for track", i_track);
340 p_vcdplayer->play_item.num = p_itemid->num;
341 p_vcdplayer->play_item.type = p_itemid->type;
342 p_vcdplayer->i_lsn = i_lsn;
343 p_vcdplayer->end_lsn = p_vcdplayer->i_lsn + i_size;
344 p_vcdplayer->origin_lsn = p_vcdplayer->i_lsn;
345 p_vcdplayer->i_track = i_track;
346 p_vcdplayer->track_lsn = vcdinfo_get_track_lsn(p_vcdplayer->vcd,
348 p_vcdplayer->track_end_lsn = p_vcdplayer->track_lsn +
349 vcdinfo_get_track_sect_count(p_vcdplayer->vcd, i_track);
351 dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN),
352 "lsn %u, end LSN: %u item.num %d, item.type %d",
353 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn,
354 p_vcdplayer->play_item.num, p_vcdplayer->play_item.type);
358 Get the next play-item in the list given in the LIDs. Note play-item
359 here refers to list of play-items for a single LID It shouldn't be
360 confused with a user's list of favorite things to play or the
361 "next" field of a LID which moves us to a different LID.
364 vcdplayer_inc_play_item(access_t *p_access)
366 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
369 dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcdplayer->pdi);
371 if ( NULL == p_vcdplayer || NULL == p_vcdplayer->pxd.pld )
374 noi = vcdinf_pld_get_noi(p_vcdplayer->pxd.pld);
378 /* Handle delays like autowait or wait here? */
382 if ( p_vcdplayer->pdi < 0 || p_vcdplayer->pdi >= noi )
385 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcdplayer->pxd.pld,
387 vcdinfo_itemid_t trans_itemid;
389 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
391 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
392 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
393 p_vcdplayer->pdi, vcdinfo_pin2str (trans_itemid_num));
394 return vcdplayer_play_single_item(p_access, trans_itemid);
398 vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid)
400 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
402 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d itemid.type: %d",
403 itemid.num, itemid.type);
405 if (!vcdplayer_pbc_is_on(p_vcdplayer)) {
406 vcdplayer_play_single_item(p_access, itemid);
408 /* PBC on - Itemid.num is LID. */
410 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
412 if (p_vcdinfo == NULL)
415 p_vcdplayer->i_lid = itemid.num;
416 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), itemid.num);
418 switch (p_vcdplayer->pxd.descriptor_type) {
420 case PSD_TYPE_SELECTION_LIST:
421 case PSD_TYPE_EXT_SELECTION_LIST: {
422 vcdinfo_itemid_t trans_itemid;
423 uint16_t trans_itemid_num;
425 if (p_vcdplayer->pxd.psd == NULL) return;
426 trans_itemid_num = vcdinf_psd_get_itemid(p_vcdplayer->pxd.psd);
427 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
428 p_vcdplayer->i_loop = 1;
429 p_vcdplayer->loop_item = trans_itemid;
430 vcdplayer_play_single_item(p_access, trans_itemid);
434 case PSD_TYPE_PLAY_LIST: {
435 if (p_vcdplayer->pxd.pld == NULL) return;
436 p_vcdplayer->pdi = -1;
437 vcdplayer_inc_play_item(p_access);
441 case PSD_TYPE_END_LIST:
442 case PSD_TYPE_COMMAND_LIST:
450 /* Handles PBC navigation when reaching the end of a play item. */
451 static vcdplayer_read_status_t
452 vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time )
454 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
456 /* We are in playback control. */
457 vcdinfo_itemid_t itemid;
459 /* The end of an entry is really the end of the associated
460 sequence (or track). */
462 if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) &&
463 (p_vcdplayer->i_lsn < p_vcdplayer->end_lsn) ) {
464 /* Set up to just continue to the next entry */
465 p_vcdplayer->play_item.num++;
466 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
467 "continuing into next entry: %u", p_vcdplayer->play_item.num);
468 vcdplayer_play_single_item( p_access, p_vcdplayer->play_item );
469 /* p_vcdplayer->update_title(); */
473 switch (p_vcdplayer->pxd.descriptor_type) {
474 case PSD_TYPE_END_LIST:
477 case PSD_TYPE_PLAY_LIST: {
478 if (vcdplayer_inc_play_item(p_access))
481 /* Set up for caller process wait time given. */
482 if (p_vcdplayer->i_still) {
483 *wait_time = vcdinf_get_wait_time(p_vcdplayer->pxd.pld);
484 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
485 "playlist wait time: %d", *wait_time);
486 return READ_STILL_FRAME;
489 /* Wait time has been processed; continue with next entry. */
490 vcdplayer_update_entry( p_access,
491 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
492 &itemid.num, "next" );
493 itemid.type = VCDINFO_ITEM_TYPE_LID;
494 vcdplayer_play( p_access, itemid );
497 case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
498 case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
500 uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcdplayer->pxd.psd);
501 uint16_t max_loop = vcdinf_get_loop_count(p_vcdplayer->pxd.psd);
502 vcdinfo_offset_t *offset_timeout_LID =
503 vcdinfo_get_offset_t(p_vcdplayer->vcd, timeout_offs);
505 dbg_print(INPUT_DBG_PBC, "looped: %d, max_loop %d",
506 p_vcdplayer->i_loop, max_loop);
508 /* Set up for caller process wait time given. */
509 if (p_vcdplayer->i_still) {
510 *wait_time = vcdinf_get_timeout_time(p_vcdplayer->pxd.psd);
511 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
512 "playlist wait_time: %d", *wait_time);
513 return READ_STILL_FRAME;
516 /* Wait time has been processed; continue with next entry. */
517 /* Handle any looping given. */
518 if ( max_loop == 0 || p_vcdplayer->i_loop < max_loop ) {
519 p_vcdplayer->i_loop++;
520 if (p_vcdplayer->i_loop == 0x7f) p_vcdplayer->i_loop = 0;
521 vcdplayer_play_single_item(p_access, p_vcdplayer->loop_item);
522 /* if (p_vcdplayer->i_still) p_vcdplayer->force_redisplay();*/
526 /* Looping finished and wait finished. Move to timeout
527 entry or next entry, or handle still. */
529 if (NULL != offset_timeout_LID) {
530 /* Handle timeout_LID */
531 itemid.num = offset_timeout_LID->lid;
532 itemid.type = VCDINFO_ITEM_TYPE_LID;
533 dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
534 vcdplayer_play( p_access, itemid );
537 int i_selections = vcdinf_get_num_selections(p_vcdplayer->pxd.psd);
538 if (i_selections > 0) {
539 /* Pick a random selection. */
540 unsigned int bsn=vcdinf_get_bsn(p_vcdplayer->pxd.psd);
541 int rand_selection=bsn +
542 ((unsigned)vlc_lrand48() % (unsigned)i_selections);
543 lid_t rand_lid=vcdinfo_selection_get_lid (p_vcdplayer->vcd,
546 itemid.num = rand_lid;
547 itemid.type = VCDINFO_ITEM_TYPE_LID;
548 dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
549 rand_selection - bsn, rand_lid);
550 vcdplayer_play( p_access, itemid );
552 } else if (p_vcdplayer->i_still) {
553 /* Hack: Just go back and do still again */
555 return READ_STILL_FRAME;
560 case VCDINFO_ITEM_TYPE_NOTFOUND:
561 LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
563 case VCDINFO_ITEM_TYPE_SPAREID2:
564 LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
566 case VCDINFO_ITEM_TYPE_LID:
567 LOG_ERR( "LID in PBC -- not supposed to happen" );
573 /* FIXME: Should handle autowait ... */
579 Read block into p_buf and return the status back.
581 This routine is a bit complicated because on reaching the end of
582 a track or entry we may automatically advance to the item, or
583 interpret the next item in the playback-control list.
585 vcdplayer_read_status_t
586 vcdplayer_read (access_t * p_access, uint8_t *p_buf)
589 /* p_access->handle_events (); */
592 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
593 if ( p_vcdplayer->i_lsn > p_vcdplayer->end_lsn ) {
594 vcdplayer_read_status_t read_status;
596 /* We've run off of the end of this entry. Do we continue or stop? */
597 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
598 "end reached, cur: %u, end: %u\n",
599 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
601 handle_item_continuation:
602 read_status = vcdplayer_pbc_is_on( p_vcdplayer )
603 ? vcdplayer_pbc_nav( p_access, &wait_time )
604 : vcdplayer_non_pbc_nav( p_access, &wait_time );
606 if (READ_STILL_FRAME == read_status) {
608 return READ_STILL_FRAME;
611 if (READ_BLOCK != read_status) return read_status;
614 /* Read the next block.
616 Important note: we probably speed things up by removing "data"
617 and the memcpy to it by extending vcd_image_source_read_mode2
618 to allow a mode to do what's below in addition to its
619 "raw" and "block" mode. It also would probably improve the modularity
620 a little bit as well.
624 CdIo *p_img = vcdinfo_get_cd_image(p_vcdplayer->vcd);
626 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
627 uint8_t data [M2F2_SECTOR_SIZE];
630 vcdsector_t vcd_sector;
633 if (cdio_read_mode2_sector(p_img, &vcd_sector,
634 p_vcdplayer->i_lsn, true)!=0) {
635 dbg_print(INPUT_DBG_LSN, "read error\n");
636 p_vcdplayer->i_lsn++;
639 p_vcdplayer->i_lsn++;
641 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) {
642 /* We've run off of the end of this entry. Do we continue or stop? */
643 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
644 "end reached in reading, cur: %u, end: %u\n",
645 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
649 /* Check header ID for a padding sector and simply discard
650 these. It is alleged that VCD's put these in to keep the
653 } while((vcd_sector.subheader[2]&~0x01)==0x60);
655 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn )
656 /* We've run off of the end of this entry. Do we continue or stop? */
657 goto handle_item_continuation;
659 memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE);
665 Play item assocated with the "default" selection.
667 Return false if there was some problem.
670 vcdplayer_play_default( access_t * p_access )
672 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
674 vcdinfo_itemid_t itemid;
677 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
678 "null p_vcdplayer" );
683 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
684 "current: %d" , p_vcdplayer->play_item.num);
686 itemid.type = p_vcdplayer->play_item.type;
688 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
690 #if defined(LIBVCD_VERSION)
691 lid_t lid=vcdinfo_get_multi_default_lid(p_vcdplayer->vcd, p_vcdplayer->i_lid,
694 if (VCDINFO_INVALID_LID != lid) {
696 itemid.type = VCDINFO_ITEM_TYPE_LID;
697 dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num);
699 dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcdplayer->i_lid);
704 vcdinfo_lid_get_pxd(p_vcdplayer->vcd, &(p_vcdplayer->pxd),
707 switch (p_vcdplayer->pxd.descriptor_type) {
708 case PSD_TYPE_SELECTION_LIST:
709 case PSD_TYPE_EXT_SELECTION_LIST:
710 if (p_vcdplayer->pxd.psd == NULL) return false;
711 vcdplayer_update_entry(p_access,
712 vcdinfo_get_default_offset(p_vcdplayer->vcd,
714 &itemid.num, "default");
717 case PSD_TYPE_PLAY_LIST:
718 case PSD_TYPE_END_LIST:
719 case PSD_TYPE_COMMAND_LIST:
720 LOG_WARN( "There is no PBC 'default' selection here" );
723 #endif /* LIBVCD_VERSION (< 0.7.21) */
728 /* PBC is not on. "default" selection beginning of current
731 itemid.num = p_vcdplayer->play_item.num;
735 /** ??? p_vcdplayer->update_title(); ***/
736 vcdplayer_play( p_access, itemid );
742 Play item assocated with the "next" selection.
744 Return false if there was some problem.
747 vcdplayer_play_next( access_t * p_access )
749 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
751 vcdinfo_obj_t *p_vcdinfo;
752 vcdinfo_itemid_t itemid;
754 if (!p_vcdplayer) return false;
756 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
757 "current: %d" , p_vcdplayer->play_item.num);
759 p_vcdinfo = p_vcdplayer->vcd;
761 itemid = p_vcdplayer->play_item;
763 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
765 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
767 switch (p_vcdplayer->pxd.descriptor_type) {
768 case PSD_TYPE_SELECTION_LIST:
769 case PSD_TYPE_EXT_SELECTION_LIST:
770 if (p_vcdplayer->pxd.psd == NULL) return false;
771 vcdplayer_update_entry(p_access,
772 vcdinf_psd_get_next_offset(p_vcdplayer->pxd.psd),
773 &itemid.num, "next");
774 itemid.type = VCDINFO_ITEM_TYPE_LID;
777 case PSD_TYPE_PLAY_LIST:
778 if (p_vcdplayer->pxd.pld == NULL) return false;
779 vcdplayer_update_entry(p_access,
780 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
781 &itemid.num, "next");
782 itemid.type = VCDINFO_ITEM_TYPE_LID;
785 case PSD_TYPE_END_LIST:
786 case PSD_TYPE_COMMAND_LIST:
787 LOG_WARN( "There is no PBC 'next' selection here" );
792 /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
796 switch (p_vcdplayer->play_item.type) {
797 case VCDINFO_ITEM_TYPE_ENTRY:
798 case VCDINFO_ITEM_TYPE_SEGMENT:
799 case VCDINFO_ITEM_TYPE_TRACK:
801 switch (p_vcdplayer->play_item.type) {
802 case VCDINFO_ITEM_TYPE_ENTRY:
803 max_entry = p_vcdplayer->i_entries;
805 case VCDINFO_ITEM_TYPE_SEGMENT:
806 max_entry = p_vcdplayer->i_segments;
808 case VCDINFO_ITEM_TYPE_TRACK:
809 max_entry = p_vcdplayer->i_tracks;
811 default: ; /* Handle exceptional cases below */
814 if (p_vcdplayer->play_item.num+1 < max_entry) {
815 itemid.num = p_vcdplayer->play_item.num+1;
817 LOG_WARN( "At the end - non-PBC 'next' not possible here" );
823 case VCDINFO_ITEM_TYPE_LID:
824 /* Should have handled above. */
825 LOG_WARN( "Internal inconsistency - should not have gotten here." );
832 /** ??? p_vcdplayer->update_title(); ***/
833 vcdplayer_play( p_access, itemid );
839 Play item assocated with the "prev" selection.
841 Return false if there was some problem.
844 vcdplayer_play_prev( access_t * p_access )
846 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
847 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
848 vcdinfo_itemid_t itemid;
850 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
851 "current: %d" , p_vcdplayer->play_item.num);
853 itemid = p_vcdplayer->play_item;
855 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
857 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
859 switch (p_vcdplayer->pxd.descriptor_type) {
860 case PSD_TYPE_SELECTION_LIST:
861 case PSD_TYPE_EXT_SELECTION_LIST:
862 if (p_vcdplayer->pxd.psd == NULL) return false;
863 vcdplayer_update_entry(p_access,
864 vcdinf_psd_get_prev_offset(p_vcdplayer->pxd.psd),
865 &itemid.num, "prev");
866 itemid.type = VCDINFO_ITEM_TYPE_LID;
869 case PSD_TYPE_PLAY_LIST:
870 if (p_vcdplayer->pxd.pld == NULL) return false;
871 vcdplayer_update_entry(p_access,
872 vcdinf_pld_get_prev_offset(p_vcdplayer->pxd.pld),
873 &itemid.num, "prev");
874 itemid.type = VCDINFO_ITEM_TYPE_LID;
877 case PSD_TYPE_END_LIST:
878 case PSD_TYPE_COMMAND_LIST:
879 LOG_WARN( "There is no PBC 'prev' selection here" );
884 /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
886 int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
889 if (p_vcdplayer->play_item.num > min_entry) {
890 itemid.num = p_vcdplayer->play_item.num-1;
892 LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
898 /** ??? p_vcdplayer->update_title(); ***/
899 vcdplayer_play( p_access, itemid );
905 Play item assocated with the "return" selection.
907 Return false if there was some problem.
910 vcdplayer_play_return( access_t * p_access )
912 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
913 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
914 vcdinfo_itemid_t itemid;
916 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
917 "current: %d" , p_vcdplayer->play_item.num);
919 itemid = p_vcdplayer->play_item;
921 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
923 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
925 switch (p_vcdplayer->pxd.descriptor_type) {
926 case PSD_TYPE_SELECTION_LIST:
927 case PSD_TYPE_EXT_SELECTION_LIST:
928 if (p_vcdplayer->pxd.psd == NULL) return false;
929 vcdplayer_update_entry(p_access,
930 vcdinf_psd_get_return_offset(p_vcdplayer->pxd.psd),
931 &itemid.num, "return");
932 itemid.type = VCDINFO_ITEM_TYPE_LID;
935 case PSD_TYPE_PLAY_LIST:
936 if (p_vcdplayer->pxd.pld == NULL) return false;
937 vcdplayer_update_entry(p_access,
938 vcdinf_pld_get_return_offset(p_vcdplayer->pxd.pld),
939 &itemid.num, "return");
940 itemid.type = VCDINFO_ITEM_TYPE_LID;
943 case PSD_TYPE_END_LIST:
944 case PSD_TYPE_COMMAND_LIST:
945 LOG_WARN( "There is no PBC 'return' selection here" );
950 /* PBC is not on. "Return" selection is min_entry if possible. */
952 p_vcdplayer->play_item.num =
953 (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
958 /** ??? p_vcdplayer->update_title(); ***/
959 vcdplayer_play( p_access, itemid );