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_vcdplayer )
59 return VCDINFO_INVALID_ENTRY != p_vcdplayer->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_vcdplayer= (vcdplayer_t *)p_access->p_sys;
69 switch (itemid.type) {
70 case VCDINFO_ITEM_TYPE_ENTRY:
71 return p_vcdplayer->entry[itemid.num].size;
73 case VCDINFO_ITEM_TYPE_SEGMENT:
74 return p_vcdplayer->segment[itemid.num].size;
76 case VCDINFO_ITEM_TYPE_TRACK:
77 return p_vcdplayer->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_vcdplayer= (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_vcdplayer->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_vcdplayer= (vcdplayer_t *)p_access->p_sys;
121 /* Not in playback control. Do we advance automatically or stop? */
122 switch (p_vcdplayer->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),
134 if (p_vcdplayer->in_still)
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 */
151 if (p_vcdplayer->in_still)
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_vcdplayer = (vcdplayer_t *)p_access->p_sys;
170 if (i_track < 1 || i_track > p_vcdplayer->i_tracks)
173 vcdinfo_obj_t *p_obj = p_vcdplayer->vcd;
174 vcdinfo_itemid_t itemid;
176 itemid.num = i_track;
177 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
178 p_vcdplayer->in_still = 0;
180 VCDSetOrigin(p_access, vcdinfo_get_track_lsn(p_obj, i_track),
183 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
188 Set reading to play an entry
191 _vcdplayer_set_entry(access_t * p_access, unsigned int num)
193 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
194 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
195 unsigned int num_entries = vcdinfo_get_num_entries(p_vcdinfo);
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;
205 p_vcdplayer->in_still = 0;
207 VCDSetOrigin(p_access, vcdinfo_get_entry_lba(p_vcdinfo, num),
208 vcdinfo_get_track(p_vcdinfo, num), &itemid);
210 dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u",
211 p_vcdplayer->i_lsn, p_vcdplayer->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_vcdplayer = (vcdplayer_t *)p_access->p_sys;
222 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
223 segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
226 LOG_ERR("%s %d", _("bad segment number"), num);
229 vcdinfo_itemid_t itemid;
231 if (VCDINFO_NULL_LSN==p_vcdplayer->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_vcdinfo, num), 0, &itemid);
242 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
247 /* Play a single item. */
249 vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
251 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
252 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
254 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d, itemid.type: %d",
255 itemid.num, itemid.type);
257 p_vcdplayer->in_still = 0;
259 switch (itemid.type) {
260 case VCDINFO_ITEM_TYPE_SEGMENT:
262 vcdinfo_video_segment_type_t segtype
263 = vcdinfo_get_video_type(p_vcdinfo, itemid.num);
264 segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
266 dbg_print(INPUT_DBG_PBC, "%s (%d), itemid.num: %d",
267 vcdinfo_video_type2str(p_vcdinfo, itemid.num),
268 (int) segtype, itemid.num);
270 if (itemid.num >= i_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_vcdplayer->in_still = -5;
282 p_vcdplayer->in_still = 0;
288 case VCDINFO_ITEM_TYPE_TRACK:
289 dbg_print(INPUT_DBG_PBC, "track %d", itemid.num);
290 if (itemid.num < 1 || itemid.num > p_vcdplayer->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_vcdinfo);
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_vcdplayer above"));
308 case VCDINFO_ITEM_TYPE_NOTFOUND:
309 dbg_print(INPUT_DBG_PBC, "play nothing");
310 p_vcdplayer->i_lsn = p_vcdplayer->end_lsn;
314 LOG_ERR("item type %d not implemented.", itemid.type);
318 p_vcdplayer->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_vcdplayer->flush_buffers)
323 p_vcdplayer->flush_buffers(); */
328 Set's start origin and size for subsequent seeks.
329 input: p_vcdplayer->i_lsn, p_vcdplayer->play_item
330 changed: p_vcdplayer->origin_lsn, p_vcdplayer->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_vcdplayer = (vcdplayer_t *)p_access->p_sys;
339 const size_t i_size= vcdplayer_get_item_size(p_access, *p_itemid);
341 p_vcdplayer->play_item.num = p_itemid->num;
342 p_vcdplayer->play_item.type = p_itemid->type;
343 p_vcdplayer->i_lsn = i_lsn;
344 p_vcdplayer->end_lsn = p_vcdplayer->i_lsn + i_size;
345 p_vcdplayer->origin_lsn = p_vcdplayer->i_lsn;
346 p_vcdplayer->i_track = i_track;
347 p_vcdplayer->track_lsn = vcdinfo_get_track_lba(p_vcdplayer->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_vcdplayer->i_lsn, p_vcdplayer->end_lsn,
352 p_vcdplayer->play_item.num, p_vcdplayer->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)
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 ) return false;
372 noi = vcdinf_pld_get_noi(p_vcdplayer->pxd.pld);
374 if ( noi <= 0 ) return false;
376 /* Handle delays like autowait or wait here? */
380 if ( p_vcdplayer->pdi < 0 || p_vcdplayer->pdi >= noi ) return false;
383 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcdplayer->pxd.pld,
385 vcdinfo_itemid_t trans_itemid;
387 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
389 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
390 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
391 p_vcdplayer->pdi, vcdinfo_pin2str (trans_itemid_num));
392 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 *obj = p_vcdplayer->vcd;
411 if (obj == NULL) return;
413 p_vcdplayer->i_lid = itemid.num;
414 vcdinfo_lid_get_pxd(obj, &(p_vcdplayer->pxd), itemid.num);
416 switch (p_vcdplayer->pxd.descriptor_type) {
418 case PSD_TYPE_SELECTION_LIST:
419 case PSD_TYPE_EXT_SELECTION_LIST: {
420 vcdinfo_itemid_t trans_itemid;
421 uint16_t trans_itemid_num;
423 if (p_vcdplayer->pxd.psd == NULL) return;
424 trans_itemid_num = vcdinf_psd_get_itemid(p_vcdplayer->pxd.psd);
425 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
426 p_vcdplayer->i_loop = 1;
427 p_vcdplayer->loop_item = trans_itemid;
428 vcdplayer_play_single_item(p_access, trans_itemid);
432 case PSD_TYPE_PLAY_LIST: {
433 if (p_vcdplayer->pxd.pld == NULL) return;
434 p_vcdplayer->pdi = -1;
435 vcdplayer_inc_play_item(p_access);
439 case PSD_TYPE_END_LIST:
440 case PSD_TYPE_COMMAND_LIST:
448 /* Handles PBC navigation when reaching the end of a play item. */
449 vcdplayer_read_status_t
450 vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time )
452 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
454 /* We are in playback control. */
455 vcdinfo_itemid_t itemid;
457 /* The end of an entry is really the end of the associated
458 sequence (or track). */
460 if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) &&
461 (p_vcdplayer->i_lsn < p_vcdplayer->end_lsn) ) {
462 /* Set up to just continue to the next entry */
463 p_vcdplayer->play_item.num++;
464 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
465 "continuing into next entry: %u", p_vcdplayer->play_item.num);
466 vcdplayer_play_single_item( p_access, p_vcdplayer->play_item );
467 /* p_vcdplayer->update_title(); */
471 switch (p_vcdplayer->pxd.descriptor_type) {
472 case PSD_TYPE_END_LIST:
475 case PSD_TYPE_PLAY_LIST: {
476 if (vcdplayer_inc_play_item(p_access))
479 /* Set up for caller process wait time given. */
480 if (p_vcdplayer->in_still) {
481 *wait_time = vcdinf_get_wait_time(p_vcdplayer->pxd.pld);
482 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
483 "playlist wait time: %d", *wait_time);
484 return READ_STILL_FRAME;
487 /* Wait time has been processed; continue with next entry. */
488 vcdplayer_update_entry( p_access,
489 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
490 &itemid.num, "next" );
491 itemid.type = VCDINFO_ITEM_TYPE_LID;
492 vcdplayer_play( p_access, itemid );
495 case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
496 case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
498 uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcdplayer->pxd.psd);
499 uint16_t max_loop = vcdinf_get_loop_count(p_vcdplayer->pxd.psd);
500 vcdinfo_offset_t *offset_timeout_LID =
501 vcdinfo_get_offset_t(p_vcdplayer->vcd, timeout_offs);
503 dbg_print(INPUT_DBG_PBC, "looped: %d, max_loop %d",
504 p_vcdplayer->i_loop, max_loop);
506 /* Set up for caller process wait time given. */
507 if (p_vcdplayer->in_still) {
508 *wait_time = vcdinf_get_timeout_time(p_vcdplayer->pxd.psd);
509 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
510 "playlist wait_time: %d", *wait_time);
511 return READ_STILL_FRAME;
514 /* Wait time has been processed; continue with next entry. */
515 /* Handle any looping given. */
516 if ( max_loop == 0 || p_vcdplayer->i_loop < max_loop ) {
517 p_vcdplayer->i_loop++;
518 if (p_vcdplayer->i_loop == 0x7f) p_vcdplayer->i_loop = 0;
519 VCDSeek( p_access, 0 );
520 /* if (p_vcdplayer->in_still) p_vcdplayer->force_redisplay();*/
524 /* Looping finished and wait finished. Move to timeout
525 entry or next entry, or handle still. */
527 if (NULL != offset_timeout_LID) {
528 /* Handle timeout_LID */
529 itemid.num = offset_timeout_LID->lid;
530 itemid.type = VCDINFO_ITEM_TYPE_LID;
531 dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
532 vcdplayer_play( p_access, itemid );
535 int i_selections = vcdinf_get_num_selections(p_vcdplayer->pxd.psd);
536 if (i_selections > 0) {
537 /* Pick a random selection. */
538 unsigned int bsn=vcdinf_get_bsn(p_vcdplayer->pxd.psd);
539 int rand_selection=bsn +
540 (int) ((i_selections+0.0)*rand()/(RAND_MAX+1.0));
541 lid_t rand_lid=vcdinfo_selection_get_lid (p_vcdplayer->vcd,
544 itemid.num = rand_lid;
545 itemid.type = VCDINFO_ITEM_TYPE_LID;
546 dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
547 rand_selection - bsn, rand_lid);
548 vcdplayer_play( p_access, itemid );
550 } else if (p_vcdplayer->in_still) {
551 /* Hack: Just go back and do still again */
553 return READ_STILL_FRAME;
558 case VCDINFO_ITEM_TYPE_NOTFOUND:
559 LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
561 case VCDINFO_ITEM_TYPE_SPAREID2:
562 LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
564 case VCDINFO_ITEM_TYPE_LID:
565 LOG_ERR( "LID in PBC -- not supposed to happen" );
571 /* FIXME: Should handle autowait ... */
577 Read block into p_buf and return the status back.
579 This routine is a bit complicated because on reaching the end of
580 a track or entry we may automatically advance to the item, or
581 interpret the next item in the playback-control list.
583 vcdplayer_read_status_t
584 vcdplayer_read (access_t * p_access, uint8_t *p_buf)
587 /* p_access->handle_events (); */
590 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
591 if ( p_vcdplayer->i_lsn > p_vcdplayer->end_lsn ) {
592 vcdplayer_read_status_t read_status;
594 /* We've run off of the end of this entry. Do we continue or stop? */
595 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
596 "end reached, cur: %u, end: %u\n", p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
598 handle_item_continuation:
599 read_status = vcdplayer_pbc_is_on( p_vcdplayer )
600 ? vcdplayer_pbc_nav( p_access, &wait_time )
601 : vcdplayer_non_pbc_nav( p_access, &wait_time );
603 if (READ_STILL_FRAME == read_status) {
605 return READ_STILL_FRAME;
608 if (READ_BLOCK != read_status) return read_status;
611 /* Read the next block.
613 Important note: we probably speed things up by removing "data"
614 and the memcpy to it by extending vcd_image_source_read_mode2
615 to allow a mode to do what's below in addition to its
616 "raw" and "block" mode. It also would probably improve the modularity
617 a little bit as well.
621 CdIo *p_img = vcdinfo_get_cd_image(p_vcdplayer->vcd);
623 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
624 uint8_t data [M2F2_SECTOR_SIZE];
627 vcdsector_t vcd_sector;
630 if (cdio_read_mode2_sector(p_img, &vcd_sector, p_vcdplayer->i_lsn, true)!=0) {
631 dbg_print(INPUT_DBG_LSN, "read error\n");
632 p_vcdplayer->i_lsn++;
635 p_vcdplayer->i_lsn++;
637 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) {
638 /* We've run off of the end of p_vcdplayer entry. Do we continue or stop? */
639 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
640 "end reached in reading, cur: %u, end: %u\n",
641 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
645 /* Check header ID for a padding sector and simply discard
646 these. It is alleged that VCD's put these in to keep the
649 } while((vcd_sector.subheader[2]&~0x01)==0x60);
651 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn )
652 /* We've run off of the end of this entry. Do we continue or stop? */
653 goto handle_item_continuation;
655 memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE);
661 Play item assocated with the "default" selection.
663 Return false if there was some problem.
666 vcdplayer_play_default( access_t * p_access )
668 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
670 vcdinfo_itemid_t itemid;
673 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
674 "null p_vcdplayer" );
679 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
680 "current: %d" , p_vcdplayer->play_item.num);
682 itemid.type = p_vcdplayer->play_item.type;
684 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
686 #if defined(LIBVCD_VERSION)
687 lid_t lid=vcdinfo_get_multi_default_lid(p_vcdplayer->vcd, p_vcdplayer->i_lid,
690 if (VCDINFO_INVALID_LID != lid) {
692 itemid.type = VCDINFO_ITEM_TYPE_LID;
693 dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num);
695 dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcdplayer->i_lid);
699 vcdinfo_lid_get_pxd(p_vcdplayer->vcd, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
701 switch (p_vcdplayer->pxd.descriptor_type) {
702 case PSD_TYPE_SELECTION_LIST:
703 case PSD_TYPE_EXT_SELECTION_LIST:
704 if (p_vcdplayer->pxd.psd == NULL) return false;
705 vcdplayer_update_entry( p_access,
706 vcdinfo_get_default_offset(p_vcdplayer->vcd,
708 &itemid.num, "default");
711 case PSD_TYPE_PLAY_LIST:
712 case PSD_TYPE_END_LIST:
713 case PSD_TYPE_COMMAND_LIST:
714 LOG_WARN( "There is no PBC 'default' selection here" );
717 #endif /* LIBVCD_VERSION (< 0.7.21) */
722 /* PBC is not on. "default" selection beginning of current
725 p_vcdplayer->play_item.num = p_vcdplayer->play_item.num;
729 /** ??? p_vcdplayer->update_title(); ***/
730 vcdplayer_play( p_access, itemid );
736 Play item assocated with the "next" selection.
738 Return false if there was some problem.
741 vcdplayer_play_next( access_t * p_access )
743 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
745 vcdinfo_obj_t *p_vcdinfo;
746 vcdinfo_itemid_t itemid;
748 if (!p_vcdplayer) return false;
750 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
751 "current: %d" , p_vcdplayer->play_item.num);
753 p_vcdinfo = p_vcdplayer->vcd;
755 itemid.type = p_vcdplayer->play_item.type;
757 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
759 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
761 switch (p_vcdplayer->pxd.descriptor_type) {
762 case PSD_TYPE_SELECTION_LIST:
763 case PSD_TYPE_EXT_SELECTION_LIST:
764 if (p_vcdplayer->pxd.psd == NULL) return false;
765 vcdplayer_update_entry( p_access,
766 vcdinf_psd_get_next_offset(p_vcdplayer->pxd.psd),
767 &itemid.num, "next");
768 itemid.type = VCDINFO_ITEM_TYPE_LID;
771 case PSD_TYPE_PLAY_LIST:
772 if (p_vcdplayer->pxd.pld == NULL) return false;
773 vcdplayer_update_entry( p_access,
774 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
775 &itemid.num, "next");
776 itemid.type = VCDINFO_ITEM_TYPE_LID;
779 case PSD_TYPE_END_LIST:
780 case PSD_TYPE_COMMAND_LIST:
781 LOG_WARN( "There is no PBC 'next' selection here" );
786 /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
790 switch (p_vcdplayer->play_item.type) {
791 case VCDINFO_ITEM_TYPE_ENTRY:
792 case VCDINFO_ITEM_TYPE_SEGMENT:
793 case VCDINFO_ITEM_TYPE_TRACK:
795 switch (p_vcdplayer->play_item.type) {
796 case VCDINFO_ITEM_TYPE_ENTRY:
797 max_entry = p_vcdplayer->i_entries;
799 case VCDINFO_ITEM_TYPE_SEGMENT:
800 max_entry = p_vcdplayer->i_segments;
802 case VCDINFO_ITEM_TYPE_TRACK:
803 max_entry = p_vcdplayer->i_tracks;
805 default: ; /* Handle exceptional cases below */
808 if (p_vcdplayer->play_item.num+1 < max_entry) {
809 itemid.num = p_vcdplayer->play_item.num+1;
811 LOG_WARN( "At the end - non-PBC 'next' not possible here" );
817 case VCDINFO_ITEM_TYPE_LID:
819 /* Should have handled above. */
820 LOG_WARN( "Internal inconsistency - should not have gotten here." );
828 /** ??? p_vcdplayer->update_title(); ***/
829 vcdplayer_play( p_access, itemid );
835 Play item assocated with the "prev" selection.
837 Return false if there was some problem.
840 vcdplayer_play_prev( access_t * p_access )
842 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
843 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
844 vcdinfo_itemid_t itemid;
846 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
847 "current: %d" , p_vcdplayer->play_item.num);
849 itemid.type = p_vcdplayer->play_item.type;
851 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
853 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
855 switch (p_vcdplayer->pxd.descriptor_type) {
856 case PSD_TYPE_SELECTION_LIST:
857 case PSD_TYPE_EXT_SELECTION_LIST:
858 if (p_vcdplayer->pxd.psd == NULL) return false;
859 vcdplayer_update_entry( p_access,
860 vcdinf_psd_get_prev_offset(p_vcdplayer->pxd.psd),
861 &itemid.num, "prev");
862 itemid.type = VCDINFO_ITEM_TYPE_LID;
865 case PSD_TYPE_PLAY_LIST:
866 if (p_vcdplayer->pxd.pld == NULL) return false;
867 vcdplayer_update_entry( p_access,
868 vcdinf_pld_get_prev_offset(p_vcdplayer->pxd.pld),
869 &itemid.num, "prev");
870 itemid.type = VCDINFO_ITEM_TYPE_LID;
873 case PSD_TYPE_END_LIST:
874 case PSD_TYPE_COMMAND_LIST:
875 LOG_WARN( "There is no PBC 'prev' selection here" );
880 /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
882 int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
885 if (p_vcdplayer->play_item.num > min_entry) {
886 itemid.num = p_vcdplayer->play_item.num-1;
888 LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
894 /** ??? p_vcdplayer->update_title(); ***/
895 vcdplayer_play( p_access, itemid );
901 Play item assocated with the "return" selection.
903 Return false if there was some problem.
906 vcdplayer_play_return( access_t * p_access )
908 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
909 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
910 vcdinfo_itemid_t itemid;
912 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
913 "current: %d" , p_vcdplayer->play_item.num);
915 itemid.type = p_vcdplayer->play_item.type;
917 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
919 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
921 switch (p_vcdplayer->pxd.descriptor_type) {
922 case PSD_TYPE_SELECTION_LIST:
923 case PSD_TYPE_EXT_SELECTION_LIST:
924 if (p_vcdplayer->pxd.psd == NULL) return false;
925 vcdplayer_update_entry( p_access,
926 vcdinf_psd_get_return_offset(p_vcdplayer->pxd.psd),
927 &itemid.num, "return");
928 itemid.type = VCDINFO_ITEM_TYPE_LID;
931 case PSD_TYPE_PLAY_LIST:
932 if (p_vcdplayer->pxd.pld == NULL) return false;
933 vcdplayer_update_entry( p_access,
934 vcdinf_pld_get_return_offset(p_vcdplayer->pxd.pld),
935 &itemid.num, "return");
936 itemid.type = VCDINFO_ITEM_TYPE_LID;
939 case PSD_TYPE_END_LIST:
940 case PSD_TYPE_COMMAND_LIST:
941 LOG_WARN( "There is no PBC 'return' selection here" );
946 /* PBC is not on. "Return" selection is min_entry if possible. */
948 p_vcdplayer->play_item.num = (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
953 /** ??? p_vcdplayer->update_title(); ***/
954 vcdplayer_play( p_access, itemid );