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>
46 extern void VCDSetOrigin ( access_t *p_access, lsn_t i_lsn, track_t i_track,
47 const vcdinfo_itemid_t * p_itemid );
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 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 ) )
127 case VCDINFO_ITEM_TYPE_SPAREID2:
128 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
130 if (p_vcdplayer->in_still)
132 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
133 "End of still spareid2" );
135 return READ_STILL_FRAME ;
138 case VCDINFO_ITEM_TYPE_NOTFOUND:
139 LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen");
141 case VCDINFO_ITEM_TYPE_LID:
142 LOG_ERR ("LID outside PBC -- not supposed to happen");
144 case VCDINFO_ITEM_TYPE_SEGMENT:
145 /* Hack: Just go back and do still again */
147 if (p_vcdplayer->in_still)
149 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
150 "End of still Segment" );
152 return READ_STILL_FRAME;
160 Set reading to play an entire track.
163 _vcdplayer_set_track(access_t * p_access, track_t i_track)
165 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
166 if (i_track < 1 || i_track > p_vcdplayer->i_tracks)
169 const vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
170 vcdinfo_itemid_t itemid;
172 itemid.num = i_track;
173 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
174 p_vcdplayer->in_still = 0;
176 VCDSetOrigin(p_access, vcdinfo_get_track_lsn(p_vcdinfo, i_track),
179 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
184 Set reading to play an entry
187 _vcdplayer_set_entry(access_t * p_access, unsigned int num)
189 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
190 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
191 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
193 if (num >= i_entries) {
194 LOG_ERR("%s %d", "bad entry number", num);
197 vcdinfo_itemid_t itemid;
200 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
201 p_vcdplayer->i_still = 0;
203 VCDSetOrigin(p_access, vcdinfo_get_entry_lsn(p_vcdinfo, num),
204 vcdinfo_get_track(p_vcdinfo, num), &itemid);
206 dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u",
207 p_vcdplayer->i_lsn, p_vcdplayer->track_end_lsn);
212 Set reading to play an segment (e.g. still frame)
215 _vcdplayer_set_segment(access_t * p_access, unsigned int num)
217 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
218 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
219 segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
222 LOG_ERR("%s %d", "bad segment number", num);
225 vcdinfo_itemid_t itemid;
227 if (VCDINFO_NULL_LSN==p_vcdplayer->i_lsn) {
229 "Error in getting current segment number", num);
234 itemid.type = VCDINFO_ITEM_TYPE_SEGMENT;
236 VCDSetOrigin(p_access, vcdinfo_get_seg_lsn(p_vcdinfo, num), 0, &itemid);
238 dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
243 /* Play a single item. */
245 vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
247 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
248 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
250 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d, itemid.type: %d",
251 itemid.num, itemid.type);
253 p_vcdplayer->i_still = 0;
255 switch (itemid.type) {
256 case VCDINFO_ITEM_TYPE_SEGMENT:
258 vcdinfo_video_segment_type_t segtype
259 = vcdinfo_get_video_type(p_vcdinfo, itemid.num);
260 segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
262 dbg_print(INPUT_DBG_PBC, "%s (%d), itemid.num: %d",
263 vcdinfo_video_type2str(p_vcdinfo, itemid.num),
264 (int) segtype, itemid.num);
266 if (itemid.num >= i_segs) return false;
267 _vcdplayer_set_segment(p_access, itemid.num);
271 case VCDINFO_FILES_VIDEO_NTSC_STILL:
272 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
273 case VCDINFO_FILES_VIDEO_PAL_STILL:
274 case VCDINFO_FILES_VIDEO_PAL_STILL2:
275 p_vcdplayer->i_still = STILL_READING;
278 p_vcdplayer->i_still = 0;
284 case VCDINFO_ITEM_TYPE_TRACK:
285 dbg_print(INPUT_DBG_PBC, "track %d", itemid.num);
286 if (itemid.num < 1 || itemid.num > p_vcdplayer->i_tracks) return false;
287 _vcdplayer_set_track(p_access, itemid.num);
290 case VCDINFO_ITEM_TYPE_ENTRY:
292 unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
293 dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num);
294 if (itemid.num >= i_entries) return false;
295 _vcdplayer_set_entry(p_access, itemid.num);
299 case VCDINFO_ITEM_TYPE_LID:
300 LOG_ERR("%s", "Should have converted p_vcdplayer above");
304 case VCDINFO_ITEM_TYPE_NOTFOUND:
305 dbg_print(INPUT_DBG_PBC, "play nothing");
306 p_vcdplayer->i_lsn = p_vcdplayer->end_lsn;
310 LOG_ERR("item type %d not implemented.", itemid.type);
314 p_vcdplayer->play_item = itemid;
316 /* Some players like xine, have a fifo queue of audio and video buffers
317 that need to be flushed when playing a new selection. */
318 /* if (p_vcdplayer->flush_buffers)
319 p_vcdplayer->flush_buffers(); */
324 Set's start origin and size for subsequent seeks.
325 input: p_vcdplayer->i_lsn, p_vcdplayer->play_item
326 changed: p_vcdplayer->origin_lsn, p_vcdplayer->end_lsn
329 /* FIXME: add parameters lsn, i_track, p_itemid and set accordingly. */
331 vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track,
332 const vcdinfo_itemid_t *p_itemid)
334 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
335 const size_t i_size= vcdplayer_get_item_size(p_access, *p_itemid);
337 p_vcdplayer->play_item.num = p_itemid->num;
338 p_vcdplayer->play_item.type = p_itemid->type;
339 p_vcdplayer->i_lsn = i_lsn;
340 p_vcdplayer->end_lsn = p_vcdplayer->i_lsn + i_size;
341 p_vcdplayer->origin_lsn = p_vcdplayer->i_lsn;
342 p_vcdplayer->i_track = i_track;
343 p_vcdplayer->track_lsn = vcdinfo_get_track_lsn(p_vcdplayer->vcd,
346 dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN),
347 "lsn %u, end LSN: %u item.num %d, item.type %d",
348 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn,
349 p_vcdplayer->play_item.num, p_vcdplayer->play_item.type);
353 Get the next play-item in the list given in the LIDs. Note play-item
354 here refers to list of play-items for a single LID It shouldn't be
355 confused with a user's list of favorite things to play or the
356 "next" field of a LID which moves us to a different LID.
359 vcdplayer_inc_play_item(access_t *p_access)
362 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
365 dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcdplayer->pdi);
367 if ( NULL == p_vcdplayer || NULL == p_vcdplayer->pxd.pld ) return false;
369 noi = vcdinf_pld_get_noi(p_vcdplayer->pxd.pld);
371 if ( noi <= 0 ) return false;
373 /* Handle delays like autowait or wait here? */
377 if ( p_vcdplayer->pdi < 0 || p_vcdplayer->pdi >= noi ) return false;
380 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcdplayer->pxd.pld,
382 vcdinfo_itemid_t trans_itemid;
384 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
386 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
387 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
388 p_vcdplayer->pdi, vcdinfo_pin2str (trans_itemid_num));
389 return vcdplayer_play_single_item(p_access, trans_itemid);
394 vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid)
396 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
398 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d itemid.type: %d",
399 itemid.num, itemid.type);
401 if (!vcdplayer_pbc_is_on(p_vcdplayer)) {
402 vcdplayer_play_single_item(p_access, itemid);
404 /* PBC on - Itemid.num is LID. */
406 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
408 if (p_vcdinfo == NULL) return;
410 p_vcdplayer->i_lid = itemid.num;
411 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), itemid.num);
413 switch (p_vcdplayer->pxd.descriptor_type) {
415 case PSD_TYPE_SELECTION_LIST:
416 case PSD_TYPE_EXT_SELECTION_LIST: {
417 vcdinfo_itemid_t trans_itemid;
418 uint16_t trans_itemid_num;
420 if (p_vcdplayer->pxd.psd == NULL) return;
421 trans_itemid_num = vcdinf_psd_get_itemid(p_vcdplayer->pxd.psd);
422 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
423 p_vcdplayer->i_loop = 1;
424 p_vcdplayer->loop_item = trans_itemid;
425 vcdplayer_play_single_item(p_access, trans_itemid);
429 case PSD_TYPE_PLAY_LIST: {
430 if (p_vcdplayer->pxd.pld == NULL) return;
431 p_vcdplayer->pdi = -1;
432 vcdplayer_inc_play_item(p_access);
436 case PSD_TYPE_END_LIST:
437 case PSD_TYPE_COMMAND_LIST:
445 /* Handles PBC navigation when reaching the end of a play item. */
446 vcdplayer_read_status_t
447 vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time )
449 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
451 /* We are in playback control. */
452 vcdinfo_itemid_t itemid;
454 /* The end of an entry is really the end of the associated
455 sequence (or track). */
457 if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) &&
458 (p_vcdplayer->i_lsn < p_vcdplayer->end_lsn) ) {
459 /* Set up to just continue to the next entry */
460 p_vcdplayer->play_item.num++;
461 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
462 "continuing into next entry: %u", p_vcdplayer->play_item.num);
463 vcdplayer_play_single_item( p_access, p_vcdplayer->play_item );
464 /* p_vcdplayer->update_title(); */
468 switch (p_vcdplayer->pxd.descriptor_type) {
469 case PSD_TYPE_END_LIST:
472 case PSD_TYPE_PLAY_LIST: {
473 if (vcdplayer_inc_play_item(p_access))
476 /* Set up for caller process wait time given. */
477 if (p_vcdplayer->i_still) {
478 *wait_time = vcdinf_get_wait_time(p_vcdplayer->pxd.pld);
479 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
480 "playlist wait time: %d", *wait_time);
481 return READ_STILL_FRAME;
484 /* Wait time has been processed; continue with next entry. */
485 vcdplayer_update_entry( p_access,
486 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
487 &itemid.num, "next" );
488 itemid.type = VCDINFO_ITEM_TYPE_LID;
489 vcdplayer_play( p_access, itemid );
492 case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
493 case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
495 uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcdplayer->pxd.psd);
496 uint16_t max_loop = vcdinf_get_loop_count(p_vcdplayer->pxd.psd);
497 vcdinfo_offset_t *offset_timeout_LID =
498 vcdinfo_get_offset_t(p_vcdplayer->vcd, timeout_offs);
500 dbg_print(INPUT_DBG_PBC, "looped: %d, max_loop %d",
501 p_vcdplayer->i_loop, max_loop);
503 /* Set up for caller process wait time given. */
504 if (p_vcdplayer->i_still) {
505 *wait_time = vcdinf_get_timeout_time(p_vcdplayer->pxd.psd);
506 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
507 "playlist wait_time: %d", *wait_time);
508 return READ_STILL_FRAME;
511 /* Wait time has been processed; continue with next entry. */
512 /* Handle any looping given. */
513 if ( max_loop == 0 || p_vcdplayer->i_loop < max_loop ) {
514 p_vcdplayer->i_loop++;
515 if (p_vcdplayer->i_loop == 0x7f) p_vcdplayer->i_loop = 0;
516 vcdplayer_play_single_item(p_access, p_vcdplayer->loop_item);
517 /* if (p_vcdplayer->i_still) p_vcdplayer->force_redisplay();*/
521 /* Looping finished and wait finished. Move to timeout
522 entry or next entry, or handle still. */
524 if (NULL != offset_timeout_LID) {
525 /* Handle timeout_LID */
526 itemid.num = offset_timeout_LID->lid;
527 itemid.type = VCDINFO_ITEM_TYPE_LID;
528 dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
529 vcdplayer_play( p_access, itemid );
532 int i_selections = vcdinf_get_num_selections(p_vcdplayer->pxd.psd);
533 if (i_selections > 0) {
534 /* Pick a random selection. */
535 unsigned int bsn=vcdinf_get_bsn(p_vcdplayer->pxd.psd);
536 int rand_selection=bsn +
537 (int) ((i_selections+0.0)*rand()/(RAND_MAX+1.0));
538 lid_t rand_lid=vcdinfo_selection_get_lid (p_vcdplayer->vcd,
541 itemid.num = rand_lid;
542 itemid.type = VCDINFO_ITEM_TYPE_LID;
543 dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
544 rand_selection - bsn, rand_lid);
545 vcdplayer_play( p_access, itemid );
547 } else if (p_vcdplayer->i_still) {
548 /* Hack: Just go back and do still again */
550 return READ_STILL_FRAME;
555 case VCDINFO_ITEM_TYPE_NOTFOUND:
556 LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
558 case VCDINFO_ITEM_TYPE_SPAREID2:
559 LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
561 case VCDINFO_ITEM_TYPE_LID:
562 LOG_ERR( "LID in PBC -- not supposed to happen" );
568 /* FIXME: Should handle autowait ... */
574 Read block into p_buf and return the status back.
576 This routine is a bit complicated because on reaching the end of
577 a track or entry we may automatically advance to the item, or
578 interpret the next item in the playback-control list.
580 vcdplayer_read_status_t
581 vcdplayer_read (access_t * p_access, uint8_t *p_buf)
584 /* p_access->handle_events (); */
587 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
588 if ( p_vcdplayer->i_lsn > p_vcdplayer->end_lsn ) {
589 vcdplayer_read_status_t read_status;
591 /* We've run off of the end of this entry. Do we continue or stop? */
592 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
593 "end reached, cur: %u, end: %u\n", p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
595 handle_item_continuation:
596 read_status = vcdplayer_pbc_is_on( p_vcdplayer )
597 ? vcdplayer_pbc_nav( p_access, &wait_time )
598 : vcdplayer_non_pbc_nav( p_access, &wait_time );
600 if (READ_STILL_FRAME == read_status) {
602 return READ_STILL_FRAME;
605 if (READ_BLOCK != read_status) return read_status;
608 /* Read the next block.
610 Important note: we probably speed things up by removing "data"
611 and the memcpy to it by extending vcd_image_source_read_mode2
612 to allow a mode to do what's below in addition to its
613 "raw" and "block" mode. It also would probably improve the modularity
614 a little bit as well.
618 CdIo *p_img = vcdinfo_get_cd_image(p_vcdplayer->vcd);
620 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
621 uint8_t data [M2F2_SECTOR_SIZE];
624 vcdsector_t vcd_sector;
627 if (cdio_read_mode2_sector(p_img, &vcd_sector,
628 p_vcdplayer->i_lsn, true)!=0) {
629 dbg_print(INPUT_DBG_LSN, "read error\n");
630 p_vcdplayer->i_lsn++;
633 p_vcdplayer->i_lsn++;
635 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) {
636 /* We've run off of the end of this entry. Do we continue or stop? */
637 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
638 "end reached in reading, cur: %u, end: %u\n",
639 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
643 /* Check header ID for a padding sector and simply discard
644 these. It is alleged that VCD's put these in to keep the
647 } while((vcd_sector.subheader[2]&~0x01)==0x60);
649 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn )
650 /* We've run off of the end of this entry. Do we continue or stop? */
651 goto handle_item_continuation;
653 memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE);
659 Play item assocated with the "default" selection.
661 Return false if there was some problem.
664 vcdplayer_play_default( access_t * p_access )
666 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
668 vcdinfo_itemid_t itemid;
671 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
672 "null p_vcdplayer" );
677 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
678 "current: %d" , p_vcdplayer->play_item.num);
680 itemid.type = p_vcdplayer->play_item.type;
682 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
684 #if defined(LIBVCD_VERSION)
685 lid_t lid=vcdinfo_get_multi_default_lid(p_vcdplayer->vcd, p_vcdplayer->i_lid,
688 if (VCDINFO_INVALID_LID != lid) {
690 itemid.type = VCDINFO_ITEM_TYPE_LID;
691 dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num);
693 dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcdplayer->i_lid);
698 vcdinfo_lid_get_pxd(p_vcdplayer->vcd, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
700 switch (p_vcdplayer->pxd.descriptor_type) {
701 case PSD_TYPE_SELECTION_LIST:
702 case PSD_TYPE_EXT_SELECTION_LIST:
703 if (p_vcdplayer->pxd.psd == NULL) return false;
704 vcdplayer_update_entry( p_access,
705 vcdinfo_get_default_offset(p_vcdplayer->vcd,
707 &itemid.num, "default");
710 case PSD_TYPE_PLAY_LIST:
711 case PSD_TYPE_END_LIST:
712 case PSD_TYPE_COMMAND_LIST:
713 LOG_WARN( "There is no PBC 'default' selection here" );
716 #endif /* LIBVCD_VERSION (< 0.7.21) */
721 /* PBC is not on. "default" selection beginning of current
724 itemid.num = p_vcdplayer->play_item.num;
728 /** ??? p_vcdplayer->update_title(); ***/
729 vcdplayer_play( p_access, itemid );
735 Play item assocated with the "next" selection.
737 Return false if there was some problem.
740 vcdplayer_play_next( access_t * p_access )
742 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
744 vcdinfo_obj_t *p_vcdinfo;
745 vcdinfo_itemid_t itemid;
747 if (!p_vcdplayer) return false;
749 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
750 "current: %d" , p_vcdplayer->play_item.num);
752 p_vcdinfo = p_vcdplayer->vcd;
754 itemid = p_vcdplayer->play_item;
756 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
758 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
760 switch (p_vcdplayer->pxd.descriptor_type) {
761 case PSD_TYPE_SELECTION_LIST:
762 case PSD_TYPE_EXT_SELECTION_LIST:
763 if (p_vcdplayer->pxd.psd == NULL) return false;
764 vcdplayer_update_entry( p_access,
765 vcdinf_psd_get_next_offset(p_vcdplayer->pxd.psd),
766 &itemid.num, "next");
767 itemid.type = VCDINFO_ITEM_TYPE_LID;
770 case PSD_TYPE_PLAY_LIST:
771 if (p_vcdplayer->pxd.pld == NULL) return false;
772 vcdplayer_update_entry( p_access,
773 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
774 &itemid.num, "next");
775 itemid.type = VCDINFO_ITEM_TYPE_LID;
778 case PSD_TYPE_END_LIST:
779 case PSD_TYPE_COMMAND_LIST:
780 LOG_WARN( "There is no PBC 'next' selection here" );
785 /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
789 switch (p_vcdplayer->play_item.type) {
790 case VCDINFO_ITEM_TYPE_ENTRY:
791 case VCDINFO_ITEM_TYPE_SEGMENT:
792 case VCDINFO_ITEM_TYPE_TRACK:
794 switch (p_vcdplayer->play_item.type) {
795 case VCDINFO_ITEM_TYPE_ENTRY:
796 max_entry = p_vcdplayer->i_entries;
798 case VCDINFO_ITEM_TYPE_SEGMENT:
799 max_entry = p_vcdplayer->i_segments;
801 case VCDINFO_ITEM_TYPE_TRACK:
802 max_entry = p_vcdplayer->i_tracks;
804 default: ; /* Handle exceptional cases below */
807 if (p_vcdplayer->play_item.num+1 < max_entry) {
808 itemid.num = p_vcdplayer->play_item.num+1;
810 LOG_WARN( "At the end - non-PBC 'next' not possible here" );
816 case VCDINFO_ITEM_TYPE_LID:
818 /* Should have handled above. */
819 LOG_WARN( "Internal inconsistency - should not have gotten here." );
827 /** ??? p_vcdplayer->update_title(); ***/
828 vcdplayer_play( p_access, itemid );
834 Play item assocated with the "prev" selection.
836 Return false if there was some problem.
839 vcdplayer_play_prev( access_t * p_access )
841 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
842 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
843 vcdinfo_itemid_t itemid;
845 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
846 "current: %d" , p_vcdplayer->play_item.num);
848 itemid = p_vcdplayer->play_item;
850 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
852 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
854 switch (p_vcdplayer->pxd.descriptor_type) {
855 case PSD_TYPE_SELECTION_LIST:
856 case PSD_TYPE_EXT_SELECTION_LIST:
857 if (p_vcdplayer->pxd.psd == NULL) return false;
858 vcdplayer_update_entry( p_access,
859 vcdinf_psd_get_prev_offset(p_vcdplayer->pxd.psd),
860 &itemid.num, "prev");
861 itemid.type = VCDINFO_ITEM_TYPE_LID;
864 case PSD_TYPE_PLAY_LIST:
865 if (p_vcdplayer->pxd.pld == NULL) return false;
866 vcdplayer_update_entry( p_access,
867 vcdinf_pld_get_prev_offset(p_vcdplayer->pxd.pld),
868 &itemid.num, "prev");
869 itemid.type = VCDINFO_ITEM_TYPE_LID;
872 case PSD_TYPE_END_LIST:
873 case PSD_TYPE_COMMAND_LIST:
874 LOG_WARN( "There is no PBC 'prev' selection here" );
879 /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
881 int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
884 if (p_vcdplayer->play_item.num > min_entry) {
885 itemid.num = p_vcdplayer->play_item.num-1;
887 LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
893 /** ??? p_vcdplayer->update_title(); ***/
894 vcdplayer_play( p_access, itemid );
900 Play item assocated with the "return" selection.
902 Return false if there was some problem.
905 vcdplayer_play_return( access_t * p_access )
907 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
908 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
909 vcdinfo_itemid_t itemid;
911 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
912 "current: %d" , p_vcdplayer->play_item.num);
914 itemid = p_vcdplayer->play_item;
916 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
918 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
920 switch (p_vcdplayer->pxd.descriptor_type) {
921 case PSD_TYPE_SELECTION_LIST:
922 case PSD_TYPE_EXT_SELECTION_LIST:
923 if (p_vcdplayer->pxd.psd == NULL) return false;
924 vcdplayer_update_entry( p_access,
925 vcdinf_psd_get_return_offset(p_vcdplayer->pxd.psd),
926 &itemid.num, "return");
927 itemid.type = VCDINFO_ITEM_TYPE_LID;
930 case PSD_TYPE_PLAY_LIST:
931 if (p_vcdplayer->pxd.pld == NULL) return false;
932 vcdplayer_update_entry( p_access,
933 vcdinf_pld_get_return_offset(p_vcdplayer->pxd.pld),
934 &itemid.num, "return");
935 itemid.type = VCDINFO_ITEM_TYPE_LID;
938 case PSD_TYPE_END_LIST:
939 case PSD_TYPE_COMMAND_LIST:
940 LOG_WARN( "There is no PBC 'return' selection here" );
945 /* PBC is not on. "Return" selection is min_entry if possible. */
947 p_vcdplayer->play_item.num =
948 (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
953 /** ??? p_vcdplayer->update_title(); ***/
954 vcdplayer_play( p_access, itemid );
961 * c-file-style: "gnu"
963 * indent-tabs-mode: nil