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 const vcdinfo_obj_t *p_vcdinfo = 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_vcdinfo, 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 const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
197 if (num >= i_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->i_still = 0;
207 VCDSetOrigin(p_access, vcdinfo_get_entry_lsn(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->i_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->i_still = STILL_READING;
282 p_vcdplayer->i_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 i_entries = vcdinfo_get_num_entries(p_vcdinfo);
297 dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num);
298 if (itemid.num >= i_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_lsn(p_vcdplayer->vcd,
350 dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN),
351 "lsn %u, end LSN: %u item.num %d, item.type %d",
352 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn,
353 p_vcdplayer->play_item.num, p_vcdplayer->play_item.type);
357 Get the next play-item in the list given in the LIDs. Note play-item
358 here refers to list of play-items for a single LID It shouldn't be
359 confused with a user's list of favorite things to play or the
360 "next" field of a LID which moves us to a different LID.
363 vcdplayer_inc_play_item(access_t *p_access)
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 ) return false;
373 noi = vcdinf_pld_get_noi(p_vcdplayer->pxd.pld);
375 if ( noi <= 0 ) return false;
377 /* Handle delays like autowait or wait here? */
381 if ( p_vcdplayer->pdi < 0 || p_vcdplayer->pdi >= noi ) return false;
384 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcdplayer->pxd.pld,
386 vcdinfo_itemid_t trans_itemid;
388 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
390 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
391 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
392 p_vcdplayer->pdi, vcdinfo_pin2str (trans_itemid_num));
393 return vcdplayer_play_single_item(p_access, trans_itemid);
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) return;
414 p_vcdplayer->i_lid = itemid.num;
415 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), itemid.num);
417 switch (p_vcdplayer->pxd.descriptor_type) {
419 case PSD_TYPE_SELECTION_LIST:
420 case PSD_TYPE_EXT_SELECTION_LIST: {
421 vcdinfo_itemid_t trans_itemid;
422 uint16_t trans_itemid_num;
424 if (p_vcdplayer->pxd.psd == NULL) return;
425 trans_itemid_num = vcdinf_psd_get_itemid(p_vcdplayer->pxd.psd);
426 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
427 p_vcdplayer->i_loop = 1;
428 p_vcdplayer->loop_item = trans_itemid;
429 vcdplayer_play_single_item(p_access, trans_itemid);
433 case PSD_TYPE_PLAY_LIST: {
434 if (p_vcdplayer->pxd.pld == NULL) return;
435 p_vcdplayer->pdi = -1;
436 vcdplayer_inc_play_item(p_access);
440 case PSD_TYPE_END_LIST:
441 case PSD_TYPE_COMMAND_LIST:
449 /* Handles PBC navigation when reaching the end of a play item. */
450 vcdplayer_read_status_t
451 vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time )
453 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
455 /* We are in playback control. */
456 vcdinfo_itemid_t itemid;
458 /* The end of an entry is really the end of the associated
459 sequence (or track). */
461 if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) &&
462 (p_vcdplayer->i_lsn < p_vcdplayer->end_lsn) ) {
463 /* Set up to just continue to the next entry */
464 p_vcdplayer->play_item.num++;
465 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
466 "continuing into next entry: %u", p_vcdplayer->play_item.num);
467 vcdplayer_play_single_item( p_access, p_vcdplayer->play_item );
468 /* p_vcdplayer->update_title(); */
472 switch (p_vcdplayer->pxd.descriptor_type) {
473 case PSD_TYPE_END_LIST:
476 case PSD_TYPE_PLAY_LIST: {
477 if (vcdplayer_inc_play_item(p_access))
480 /* Set up for caller process wait time given. */
481 if (p_vcdplayer->i_still) {
482 *wait_time = vcdinf_get_wait_time(p_vcdplayer->pxd.pld);
483 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
484 "playlist wait time: %d", *wait_time);
485 return READ_STILL_FRAME;
488 /* Wait time has been processed; continue with next entry. */
489 vcdplayer_update_entry( p_access,
490 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
491 &itemid.num, "next" );
492 itemid.type = VCDINFO_ITEM_TYPE_LID;
493 vcdplayer_play( p_access, itemid );
496 case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
497 case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
499 uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcdplayer->pxd.psd);
500 uint16_t max_loop = vcdinf_get_loop_count(p_vcdplayer->pxd.psd);
501 vcdinfo_offset_t *offset_timeout_LID =
502 vcdinfo_get_offset_t(p_vcdplayer->vcd, timeout_offs);
504 dbg_print(INPUT_DBG_PBC, "looped: %d, max_loop %d",
505 p_vcdplayer->i_loop, max_loop);
507 /* Set up for caller process wait time given. */
508 if (p_vcdplayer->i_still) {
509 *wait_time = vcdinf_get_timeout_time(p_vcdplayer->pxd.psd);
510 dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
511 "playlist wait_time: %d", *wait_time);
512 return READ_STILL_FRAME;
515 /* Wait time has been processed; continue with next entry. */
516 /* Handle any looping given. */
517 if ( max_loop == 0 || p_vcdplayer->i_loop < max_loop ) {
518 p_vcdplayer->i_loop++;
519 if (p_vcdplayer->i_loop == 0x7f) p_vcdplayer->i_loop = 0;
520 vcdplayer_play_single_item(p_access, p_vcdplayer->loop_item);
521 /* if (p_vcdplayer->i_still) p_vcdplayer->force_redisplay();*/
525 /* Looping finished and wait finished. Move to timeout
526 entry or next entry, or handle still. */
528 if (NULL != offset_timeout_LID) {
529 /* Handle timeout_LID */
530 itemid.num = offset_timeout_LID->lid;
531 itemid.type = VCDINFO_ITEM_TYPE_LID;
532 dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
533 vcdplayer_play( p_access, itemid );
536 int i_selections = vcdinf_get_num_selections(p_vcdplayer->pxd.psd);
537 if (i_selections > 0) {
538 /* Pick a random selection. */
539 unsigned int bsn=vcdinf_get_bsn(p_vcdplayer->pxd.psd);
540 int rand_selection=bsn +
541 (int) ((i_selections+0.0)*rand()/(RAND_MAX+1.0));
542 lid_t rand_lid=vcdinfo_selection_get_lid (p_vcdplayer->vcd,
545 itemid.num = rand_lid;
546 itemid.type = VCDINFO_ITEM_TYPE_LID;
547 dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
548 rand_selection - bsn, rand_lid);
549 vcdplayer_play( p_access, itemid );
551 } else if (p_vcdplayer->i_still) {
552 /* Hack: Just go back and do still again */
554 return READ_STILL_FRAME;
559 case VCDINFO_ITEM_TYPE_NOTFOUND:
560 LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
562 case VCDINFO_ITEM_TYPE_SPAREID2:
563 LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
565 case VCDINFO_ITEM_TYPE_LID:
566 LOG_ERR( "LID in PBC -- not supposed to happen" );
572 /* FIXME: Should handle autowait ... */
578 Read block into p_buf and return the status back.
580 This routine is a bit complicated because on reaching the end of
581 a track or entry we may automatically advance to the item, or
582 interpret the next item in the playback-control list.
584 vcdplayer_read_status_t
585 vcdplayer_read (access_t * p_access, uint8_t *p_buf)
588 /* p_access->handle_events (); */
591 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
592 if ( p_vcdplayer->i_lsn > p_vcdplayer->end_lsn ) {
593 vcdplayer_read_status_t read_status;
595 /* We've run off of the end of this entry. Do we continue or stop? */
596 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
597 "end reached, cur: %u, end: %u\n", p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
599 handle_item_continuation:
600 read_status = vcdplayer_pbc_is_on( p_vcdplayer )
601 ? vcdplayer_pbc_nav( p_access, &wait_time )
602 : vcdplayer_non_pbc_nav( p_access, &wait_time );
604 if (READ_STILL_FRAME == read_status) {
606 return READ_STILL_FRAME;
609 if (READ_BLOCK != read_status) return read_status;
612 /* Read the next block.
614 Important note: we probably speed things up by removing "data"
615 and the memcpy to it by extending vcd_image_source_read_mode2
616 to allow a mode to do what's below in addition to its
617 "raw" and "block" mode. It also would probably improve the modularity
618 a little bit as well.
622 CdIo *p_img = vcdinfo_get_cd_image(p_vcdplayer->vcd);
624 uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
625 uint8_t data [M2F2_SECTOR_SIZE];
628 vcdsector_t vcd_sector;
631 if (cdio_read_mode2_sector(p_img, &vcd_sector,
632 p_vcdplayer->i_lsn, true)!=0) {
633 dbg_print(INPUT_DBG_LSN, "read error\n");
634 p_vcdplayer->i_lsn++;
637 p_vcdplayer->i_lsn++;
639 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) {
640 /* We've run off of the end of this entry. Do we continue or stop? */
641 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
642 "end reached in reading, cur: %u, end: %u\n",
643 p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
647 /* Check header ID for a padding sector and simply discard
648 these. It is alleged that VCD's put these in to keep the
651 } while((vcd_sector.subheader[2]&~0x01)==0x60);
653 if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn )
654 /* We've run off of the end of this entry. Do we continue or stop? */
655 goto handle_item_continuation;
657 memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE);
663 Play item assocated with the "default" selection.
665 Return false if there was some problem.
668 vcdplayer_play_default( access_t * p_access )
670 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
672 vcdinfo_itemid_t itemid;
675 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
676 "null p_vcdplayer" );
681 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
682 "current: %d" , p_vcdplayer->play_item.num);
684 itemid.type = p_vcdplayer->play_item.type;
686 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
688 #if defined(LIBVCD_VERSION)
689 lid_t lid=vcdinfo_get_multi_default_lid(p_vcdplayer->vcd, p_vcdplayer->i_lid,
692 if (VCDINFO_INVALID_LID != lid) {
694 itemid.type = VCDINFO_ITEM_TYPE_LID;
695 dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num);
697 dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcdplayer->i_lid);
701 vcdinfo_lid_get_pxd(p_vcdplayer->vcd, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
703 switch (p_vcdplayer->pxd.descriptor_type) {
704 case PSD_TYPE_SELECTION_LIST:
705 case PSD_TYPE_EXT_SELECTION_LIST:
706 if (p_vcdplayer->pxd.psd == NULL) return false;
707 vcdplayer_update_entry( p_access,
708 vcdinfo_get_default_offset(p_vcdplayer->vcd,
710 &itemid.num, "default");
713 case PSD_TYPE_PLAY_LIST:
714 case PSD_TYPE_END_LIST:
715 case PSD_TYPE_COMMAND_LIST:
716 LOG_WARN( "There is no PBC 'default' selection here" );
719 #endif /* LIBVCD_VERSION (< 0.7.21) */
724 /* PBC is not on. "default" selection beginning of current
727 p_vcdplayer->play_item.num = p_vcdplayer->play_item.num;
731 /** ??? p_vcdplayer->update_title(); ***/
732 vcdplayer_play( p_access, itemid );
738 Play item assocated with the "next" selection.
740 Return false if there was some problem.
743 vcdplayer_play_next( access_t * p_access )
745 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
747 vcdinfo_obj_t *p_vcdinfo;
748 vcdinfo_itemid_t itemid;
750 if (!p_vcdplayer) return false;
752 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
753 "current: %d" , p_vcdplayer->play_item.num);
755 p_vcdinfo = p_vcdplayer->vcd;
757 itemid.type = p_vcdplayer->play_item.type;
759 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
761 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
763 switch (p_vcdplayer->pxd.descriptor_type) {
764 case PSD_TYPE_SELECTION_LIST:
765 case PSD_TYPE_EXT_SELECTION_LIST:
766 if (p_vcdplayer->pxd.psd == NULL) return false;
767 vcdplayer_update_entry( p_access,
768 vcdinf_psd_get_next_offset(p_vcdplayer->pxd.psd),
769 &itemid.num, "next");
770 itemid.type = VCDINFO_ITEM_TYPE_LID;
773 case PSD_TYPE_PLAY_LIST:
774 if (p_vcdplayer->pxd.pld == NULL) return false;
775 vcdplayer_update_entry( p_access,
776 vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
777 &itemid.num, "next");
778 itemid.type = VCDINFO_ITEM_TYPE_LID;
781 case PSD_TYPE_END_LIST:
782 case PSD_TYPE_COMMAND_LIST:
783 LOG_WARN( "There is no PBC 'next' selection here" );
788 /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
792 switch (p_vcdplayer->play_item.type) {
793 case VCDINFO_ITEM_TYPE_ENTRY:
794 case VCDINFO_ITEM_TYPE_SEGMENT:
795 case VCDINFO_ITEM_TYPE_TRACK:
797 switch (p_vcdplayer->play_item.type) {
798 case VCDINFO_ITEM_TYPE_ENTRY:
799 max_entry = p_vcdplayer->i_entries;
801 case VCDINFO_ITEM_TYPE_SEGMENT:
802 max_entry = p_vcdplayer->i_segments;
804 case VCDINFO_ITEM_TYPE_TRACK:
805 max_entry = p_vcdplayer->i_tracks;
807 default: ; /* Handle exceptional cases below */
810 if (p_vcdplayer->play_item.num+1 < max_entry) {
811 itemid.num = p_vcdplayer->play_item.num+1;
813 LOG_WARN( "At the end - non-PBC 'next' not possible here" );
819 case VCDINFO_ITEM_TYPE_LID:
821 /* Should have handled above. */
822 LOG_WARN( "Internal inconsistency - should not have gotten here." );
830 /** ??? p_vcdplayer->update_title(); ***/
831 vcdplayer_play( p_access, itemid );
837 Play item assocated with the "prev" selection.
839 Return false if there was some problem.
842 vcdplayer_play_prev( access_t * p_access )
844 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
845 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
846 vcdinfo_itemid_t itemid;
848 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
849 "current: %d" , p_vcdplayer->play_item.num);
851 itemid.type = p_vcdplayer->play_item.type;
853 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
855 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
857 switch (p_vcdplayer->pxd.descriptor_type) {
858 case PSD_TYPE_SELECTION_LIST:
859 case PSD_TYPE_EXT_SELECTION_LIST:
860 if (p_vcdplayer->pxd.psd == NULL) return false;
861 vcdplayer_update_entry( p_access,
862 vcdinf_psd_get_prev_offset(p_vcdplayer->pxd.psd),
863 &itemid.num, "prev");
864 itemid.type = VCDINFO_ITEM_TYPE_LID;
867 case PSD_TYPE_PLAY_LIST:
868 if (p_vcdplayer->pxd.pld == NULL) return false;
869 vcdplayer_update_entry( p_access,
870 vcdinf_pld_get_prev_offset(p_vcdplayer->pxd.pld),
871 &itemid.num, "prev");
872 itemid.type = VCDINFO_ITEM_TYPE_LID;
875 case PSD_TYPE_END_LIST:
876 case PSD_TYPE_COMMAND_LIST:
877 LOG_WARN( "There is no PBC 'prev' selection here" );
882 /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
884 int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
887 if (p_vcdplayer->play_item.num > min_entry) {
888 itemid.num = p_vcdplayer->play_item.num-1;
890 LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
896 /** ??? p_vcdplayer->update_title(); ***/
897 vcdplayer_play( p_access, itemid );
903 Play item assocated with the "return" selection.
905 Return false if there was some problem.
908 vcdplayer_play_return( access_t * p_access )
910 vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
911 vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
912 vcdinfo_itemid_t itemid;
914 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
915 "current: %d" , p_vcdplayer->play_item.num);
917 itemid.type = p_vcdplayer->play_item.type;
919 if (vcdplayer_pbc_is_on(p_vcdplayer)) {
921 vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
923 switch (p_vcdplayer->pxd.descriptor_type) {
924 case PSD_TYPE_SELECTION_LIST:
925 case PSD_TYPE_EXT_SELECTION_LIST:
926 if (p_vcdplayer->pxd.psd == NULL) return false;
927 vcdplayer_update_entry( p_access,
928 vcdinf_psd_get_return_offset(p_vcdplayer->pxd.psd),
929 &itemid.num, "return");
930 itemid.type = VCDINFO_ITEM_TYPE_LID;
933 case PSD_TYPE_PLAY_LIST:
934 if (p_vcdplayer->pxd.pld == NULL) return false;
935 vcdplayer_update_entry( p_access,
936 vcdinf_pld_get_return_offset(p_vcdplayer->pxd.pld),
937 &itemid.num, "return");
938 itemid.type = VCDINFO_ITEM_TYPE_LID;
941 case PSD_TYPE_END_LIST:
942 case PSD_TYPE_COMMAND_LIST:
943 LOG_WARN( "There is no PBC 'return' selection here" );
948 /* PBC is not on. "Return" selection is min_entry if possible. */
950 p_vcdplayer->play_item.num =
951 (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
956 /** ??? p_vcdplayer->update_title(); ***/
957 vcdplayer_play( p_access, itemid );
964 * c-file-style: "gnu"
966 * indent-tabs-mode: nil