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 *****************************************************************************/
33 #include <<vlc_input.h>>
34 #include <vlc_interface.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
330 vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track,
331 const vcdinfo_itemid_t *p_itemid)
333 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
334 const size_t i_size= vcdplayer_get_item_size(p_access, *p_itemid);
336 if( VCDINFO_NULL_LSN == i_lsn )
338 LOG_ERR("%s %d", "Invalid LSN for track", i_track);
342 p_vcdplayer->play_item.num = p_itemid->num;
343 p_vcdplayer->play_item.type = p_itemid->type;
344 p_vcdplayer->i_lsn = i_lsn;
345 p_vcdplayer->end_lsn = p_vcdplayer->i_lsn + i_size;
346 p_vcdplayer->origin_lsn = p_vcdplayer->i_lsn;
347 p_vcdplayer->i_track = i_track;
348 p_vcdplayer->track_lsn = vcdinfo_get_track_lsn(p_vcdplayer->vcd,
350 p_vcdplayer->track_end_lsn = p_vcdplayer->track_lsn +
351 vcdinfo_get_track_sect_count(p_vcdplayer->vcd, i_track);
353 dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN),
354 "lsn %u, end LSN: %u item.num %d, item.type %d",
355 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn,
356 p_vcdplayer->play_item.num, p_vcdplayer->play_item.type);
360 Get the next play-item in the list given in the LIDs. Note play-item
361 here refers to list of play-items for a single LID It shouldn't be
362 confused with a user's list of favorite things to play or the
363 "next" field of a LID which moves us to a different LID.
366 vcdplayer_inc_play_item(access_t *p_access)
369 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
372 dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcdplayer->pdi);
374 if ( NULL == p_vcdplayer || NULL == p_vcdplayer->pxd.pld ) return false;
376 noi = vcdinf_pld_get_noi(p_vcdplayer->pxd.pld);
378 if ( noi <= 0 ) return false;
380 /* Handle delays like autowait or wait here? */
384 if ( p_vcdplayer->pdi < 0 || p_vcdplayer->pdi >= noi ) return false;
387 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcdplayer->pxd.pld,
389 vcdinfo_itemid_t trans_itemid;
391 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
393 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
394 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
395 p_vcdplayer->pdi, vcdinfo_pin2str (trans_itemid_num));
396 return vcdplayer_play_single_item(p_access, trans_itemid);
401 vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid)
403 vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
405 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d itemid.type: %d",
406 itemid.num, itemid.type);
408 if (!vcdplayer_pbc_is_on(p_vcdplayer)) {
409 vcdplayer_play_single_item(p_access, itemid);
411 /* PBC on - Itemid.num is LID. */
413 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
415 if (p_vcdinfo == NULL) return;
417 p_vcdplayer->i_lid = itemid.num;
418 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), itemid.num);
420 switch (p_vcdplayer->pxd.descriptor_type) {
422 case PSD_TYPE_SELECTION_LIST:
423 case PSD_TYPE_EXT_SELECTION_LIST: {
424 vcdinfo_itemid_t trans_itemid;
425 uint16_t trans_itemid_num;
427 if (p_vcdplayer->pxd.psd == NULL) return;
428 trans_itemid_num = vcdinf_psd_get_itemid(p_vcdplayer->pxd.psd);
429 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
430 p_vcdplayer->i_loop = 1;
431 p_vcdplayer->loop_item = trans_itemid;
432 vcdplayer_play_single_item(p_access, trans_itemid);
436 case PSD_TYPE_PLAY_LIST: {
437 if (p_vcdplayer->pxd.pld == NULL) return;
438 p_vcdplayer->pdi = -1;
439 vcdplayer_inc_play_item(p_access);
443 case PSD_TYPE_END_LIST:
444 case PSD_TYPE_COMMAND_LIST:
452 /* Handles PBC navigation when reaching the end of a play item. */
453 vcdplayer_read_status_t
454 vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time )
456 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
458 /* We are in playback control. */
459 vcdinfo_itemid_t itemid;
461 /* The end of an entry is really the end of the associated
462 sequence (or track). */
464 if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) &&
465 (p_vcdplayer->i_lsn < p_vcdplayer->end_lsn) ) {
466 /* Set up to just continue to the next entry */
467 p_vcdplayer->play_item.num++;
468 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
469 "continuing into next entry: %u", p_vcdplayer->play_item.num);
470 vcdplayer_play_single_item( p_access, p_vcdplayer->play_item );
471 /* p_vcdplayer->update_title(); */
475 switch (p_vcdplayer->pxd.descriptor_type) {
476 case PSD_TYPE_END_LIST:
479 case PSD_TYPE_PLAY_LIST: {
480 if (vcdplayer_inc_play_item(p_access))
483 /* Set up for caller process wait time given. */
484 if (p_vcdplayer->i_still) {
485 *wait_time = vcdinf_get_wait_time(p_vcdplayer->pxd.pld);
486 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
487 "playlist wait time: %d", *wait_time);
488 return READ_STILL_FRAME;
491 /* Wait time has been processed; continue with next entry. */
492 vcdplayer_update_entry( p_access,
493 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
494 &itemid.num, "next" );
495 itemid.type = VCDINFO_ITEM_TYPE_LID;
496 vcdplayer_play( p_access, itemid );
499 case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
500 case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
502 uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcdplayer->pxd.psd);
503 uint16_t max_loop = vcdinf_get_loop_count(p_vcdplayer->pxd.psd);
504 vcdinfo_offset_t *offset_timeout_LID =
505 vcdinfo_get_offset_t(p_vcdplayer->vcd, timeout_offs);
507 dbg_print(INPUT_DBG_PBC, "looped: %d, max_loop %d",
508 p_vcdplayer->i_loop, max_loop);
510 /* Set up for caller process wait time given. */
511 if (p_vcdplayer->i_still) {
512 *wait_time = vcdinf_get_timeout_time(p_vcdplayer->pxd.psd);
513 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
514 "playlist wait_time: %d", *wait_time);
515 return READ_STILL_FRAME;
518 /* Wait time has been processed; continue with next entry. */
519 /* Handle any looping given. */
520 if ( max_loop == 0 || p_vcdplayer->i_loop < max_loop ) {
521 p_vcdplayer->i_loop++;
522 if (p_vcdplayer->i_loop == 0x7f) p_vcdplayer->i_loop = 0;
523 vcdplayer_play_single_item(p_access, p_vcdplayer->loop_item);
524 /* if (p_vcdplayer->i_still) p_vcdplayer->force_redisplay();*/
528 /* Looping finished and wait finished. Move to timeout
529 entry or next entry, or handle still. */
531 if (NULL != offset_timeout_LID) {
532 /* Handle timeout_LID */
533 itemid.num = offset_timeout_LID->lid;
534 itemid.type = VCDINFO_ITEM_TYPE_LID;
535 dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
536 vcdplayer_play( p_access, itemid );
539 int i_selections = vcdinf_get_num_selections(p_vcdplayer->pxd.psd);
540 if (i_selections > 0) {
541 /* Pick a random selection. */
542 unsigned int bsn=vcdinf_get_bsn(p_vcdplayer->pxd.psd);
543 int rand_selection=bsn +
544 (int) ((i_selections+0.0)*rand()/(RAND_MAX+1.0));
545 lid_t rand_lid=vcdinfo_selection_get_lid (p_vcdplayer->vcd,
548 itemid.num = rand_lid;
549 itemid.type = VCDINFO_ITEM_TYPE_LID;
550 dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
551 rand_selection - bsn, rand_lid);
552 vcdplayer_play( p_access, itemid );
554 } else if (p_vcdplayer->i_still) {
555 /* Hack: Just go back and do still again */
557 return READ_STILL_FRAME;
562 case VCDINFO_ITEM_TYPE_NOTFOUND:
563 LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
565 case VCDINFO_ITEM_TYPE_SPAREID2:
566 LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
568 case VCDINFO_ITEM_TYPE_LID:
569 LOG_ERR( "LID in PBC -- not supposed to happen" );
575 /* FIXME: Should handle autowait ... */
581 Read block into p_buf and return the status back.
583 This routine is a bit complicated because on reaching the end of
584 a track or entry we may automatically advance to the item, or
585 interpret the next item in the playback-control list.
587 vcdplayer_read_status_t
588 vcdplayer_read (access_t * p_access, uint8_t *p_buf)
591 /* p_access->handle_events (); */
594 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
595 if ( p_vcdplayer->i_lsn > p_vcdplayer->end_lsn ) {
596 vcdplayer_read_status_t read_status;
598 /* We've run off of the end of this entry. Do we continue or stop? */
599 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
600 "end reached, cur: %u, end: %u\n", p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
602 handle_item_continuation:
603 read_status = vcdplayer_pbc_is_on( p_vcdplayer )
604 ? vcdplayer_pbc_nav( p_access, &wait_time )
605 : vcdplayer_non_pbc_nav( p_access, &wait_time );
607 if (READ_STILL_FRAME == read_status) {
609 return READ_STILL_FRAME;
612 if (READ_BLOCK != read_status) return read_status;
615 /* Read the next block.
617 Important note: we probably speed things up by removing "data"
618 and the memcpy to it by extending vcd_image_source_read_mode2
619 to allow a mode to do what's below in addition to its
620 "raw" and "block" mode. It also would probably improve the modularity
621 a little bit as well.
625 CdIo *p_img = vcdinfo_get_cd_image(p_vcdplayer->vcd);
627 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
628 uint8_t data [M2F2_SECTOR_SIZE];
631 vcdsector_t vcd_sector;
634 if (cdio_read_mode2_sector(p_img, &vcd_sector,
635 p_vcdplayer->i_lsn, true)!=0) {
636 dbg_print(INPUT_DBG_LSN, "read error\n");
637 p_vcdplayer->i_lsn++;
640 p_vcdplayer->i_lsn++;
642 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) {
643 /* We've run off of the end of this entry. Do we continue or stop? */
644 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
645 "end reached in reading, cur: %u, end: %u\n",
646 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
650 /* Check header ID for a padding sector and simply discard
651 these. It is alleged that VCD's put these in to keep the
654 } while((vcd_sector.subheader[2]&~0x01)==0x60);
656 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn )
657 /* We've run off of the end of this entry. Do we continue or stop? */
658 goto handle_item_continuation;
660 memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE);
666 Play item assocated with the "default" selection.
668 Return false if there was some problem.
671 vcdplayer_play_default( access_t * p_access )
673 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
675 vcdinfo_itemid_t itemid;
678 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
679 "null p_vcdplayer" );
684 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
685 "current: %d" , p_vcdplayer->play_item.num);
687 itemid.type = p_vcdplayer->play_item.type;
689 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
691 #if defined(LIBVCD_VERSION)
692 lid_t lid=vcdinfo_get_multi_default_lid(p_vcdplayer->vcd, p_vcdplayer->i_lid,
695 if (VCDINFO_INVALID_LID != lid) {
697 itemid.type = VCDINFO_ITEM_TYPE_LID;
698 dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num);
700 dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcdplayer->i_lid);
705 vcdinfo_lid_get_pxd(p_vcdplayer->vcd, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
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:
825 /* Should have handled above. */
826 LOG_WARN( "Internal inconsistency - should not have gotten here." );
834 /** ??? p_vcdplayer->update_title(); ***/
835 vcdplayer_play( p_access, itemid );
841 Play item assocated with the "prev" selection.
843 Return false if there was some problem.
846 vcdplayer_play_prev( access_t * p_access )
848 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
849 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
850 vcdinfo_itemid_t itemid;
852 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
853 "current: %d" , p_vcdplayer->play_item.num);
855 itemid = p_vcdplayer->play_item;
857 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
859 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
861 switch (p_vcdplayer->pxd.descriptor_type) {
862 case PSD_TYPE_SELECTION_LIST:
863 case PSD_TYPE_EXT_SELECTION_LIST:
864 if (p_vcdplayer->pxd.psd == NULL) return false;
865 vcdplayer_update_entry( p_access,
866 vcdinf_psd_get_prev_offset(p_vcdplayer->pxd.psd),
867 &itemid.num, "prev");
868 itemid.type = VCDINFO_ITEM_TYPE_LID;
871 case PSD_TYPE_PLAY_LIST:
872 if (p_vcdplayer->pxd.pld == NULL) return false;
873 vcdplayer_update_entry( p_access,
874 vcdinf_pld_get_prev_offset(p_vcdplayer->pxd.pld),
875 &itemid.num, "prev");
876 itemid.type = VCDINFO_ITEM_TYPE_LID;
879 case PSD_TYPE_END_LIST:
880 case PSD_TYPE_COMMAND_LIST:
881 LOG_WARN( "There is no PBC 'prev' selection here" );
886 /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
888 int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
891 if (p_vcdplayer->play_item.num > min_entry) {
892 itemid.num = p_vcdplayer->play_item.num-1;
894 LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
900 /** ??? p_vcdplayer->update_title(); ***/
901 vcdplayer_play( p_access, itemid );
907 Play item assocated with the "return" selection.
909 Return false if there was some problem.
912 vcdplayer_play_return( access_t * p_access )
914 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
915 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
916 vcdinfo_itemid_t itemid;
918 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
919 "current: %d" , p_vcdplayer->play_item.num);
921 itemid = p_vcdplayer->play_item;
923 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
925 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
927 switch (p_vcdplayer->pxd.descriptor_type) {
928 case PSD_TYPE_SELECTION_LIST:
929 case PSD_TYPE_EXT_SELECTION_LIST:
930 if (p_vcdplayer->pxd.psd == NULL) return false;
931 vcdplayer_update_entry( p_access,
932 vcdinf_psd_get_return_offset(p_vcdplayer->pxd.psd),
933 &itemid.num, "return");
934 itemid.type = VCDINFO_ITEM_TYPE_LID;
937 case PSD_TYPE_PLAY_LIST:
938 if (p_vcdplayer->pxd.pld == NULL) return false;
939 vcdplayer_update_entry( p_access,
940 vcdinf_pld_get_return_offset(p_vcdplayer->pxd.pld),
941 &itemid.num, "return");
942 itemid.type = VCDINFO_ITEM_TYPE_LID;
945 case PSD_TYPE_END_LIST:
946 case PSD_TYPE_COMMAND_LIST:
947 LOG_WARN( "There is no PBC 'return' selection here" );
952 /* PBC is not on. "Return" selection is min_entry if possible. */
954 p_vcdplayer->play_item.num =
955 (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
960 /** ??? p_vcdplayer->update_title(); ***/
961 vcdplayer_play( p_access, itemid );
968 * c-file-style: "gnu"
970 * indent-tabs-mode: nil