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)
51 Return VLC_TRUE if playback control (PBC) is on
54 vcdplayer_pbc_is_on( const vcdplayer_t *p_vcd )
56 return VCDINFO_INVALID_ENTRY != p_vcd->i_lid;
59 /* Given an itemid, return the size for the object (via information
60 previously stored when opening the vcd). */
62 vcdplayer_get_item_size(access_t * p_access, vcdinfo_itemid_t itemid)
64 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
66 switch (itemid.type) {
67 case VCDINFO_ITEM_TYPE_ENTRY:
68 return p_vcd->entry[itemid.num].size;
70 case VCDINFO_ITEM_TYPE_SEGMENT:
71 return p_vcd->segment[itemid.num].size;
73 case VCDINFO_ITEM_TYPE_TRACK:
74 return p_vcd->track[itemid.num-1].size;
76 case VCDINFO_ITEM_TYPE_LID:
77 /* Play list number (LID) */
80 case VCDINFO_ITEM_TYPE_NOTFOUND:
81 case VCDINFO_ITEM_TYPE_SPAREID2:
83 LOG_ERR("%s %d\n", _("bad item type"), itemid.type);
89 vcdplayer_update_entry( access_t * p_access, uint16_t ofs,
90 uint16_t *entry, const char *label)
92 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
94 if ( ofs == VCDINFO_INVALID_OFFSET ) {
95 *entry = VCDINFO_INVALID_ENTRY;
97 vcdinfo_offset_t *off = vcdinfo_get_offset_t(p_vcd->vcd, ofs);
100 dbg_print(INPUT_DBG_PBC, "%s: LID %d\n", label, off->lid);
102 *entry = VCDINFO_INVALID_ENTRY;
106 /* Handles navigation when NOT in PBC reaching the end of a play item.
108 The navigations rules here may be sort of made up, but the intent
109 is to do something that's probably right or helpful.
111 return VLC_TRUE if the caller should return.
113 vcdplayer_read_status_t
114 vcdplayer_non_pbc_nav ( access_t *p_access )
116 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
118 /* Not in playback control. Do we advance automatically or stop? */
119 switch (p_vcd->play_item.type) {
120 case VCDINFO_ITEM_TYPE_TRACK:
121 case VCDINFO_ITEM_TYPE_ENTRY: {
123 dbg_print( INPUT_DBG_LSN, "new track %d, lsn %d", p_vcd->i_track+1,
124 vcdinfo_get_track_lsn(p_vcd->vcd, p_vcd->i_track+1) );
128 case VCDINFO_ITEM_TYPE_SPAREID2:
129 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
134 return READ_STILL_FRAME ;
137 case VCDINFO_ITEM_TYPE_NOTFOUND:
138 LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen");
140 case VCDINFO_ITEM_TYPE_LID:
141 LOG_ERR ("LID outside PBC -- not supposed to happen");
143 case VCDINFO_ITEM_TYPE_SEGMENT:
144 /* Hack: Just go back and do still again */
148 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
149 "End of Segment - looping" );
150 return READ_STILL_FRAME;
159 Set reading to play an entire track.
162 _vcdplayer_set_track(access_t * p_access, track_t i_track)
164 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
165 if (i_track < 1 || i_track > p_vcd->i_tracks)
168 vcdinfo_obj_t *p_obj = p_vcd->vcd;
169 vcdinfo_itemid_t itemid;
171 itemid.num = i_track;
172 itemid.type = VCDINFO_ITEM_TYPE_TRACK;
174 p_vcd->i_lsn = vcdinfo_get_track_lsn(p_obj, i_track);
175 p_vcd->play_item = itemid;
176 p_vcd->i_track = i_track;
177 p_vcd->track_lsn = p_vcd->i_lsn;
179 vcdplayer_set_origin(p_access);
181 dbg_print(INPUT_DBG_LSN, "LSN: %u\n", p_vcd->i_lsn);
186 Set reading to play an entry
189 _vcdplayer_set_entry(access_t * p_access, unsigned int num)
191 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
192 vcdinfo_obj_t *p_obj = p_vcd->vcd;
193 unsigned int num_entries = vcdinfo_get_num_entries(p_obj);
195 if (num >= num_entries) {
196 LOG_ERR("%s %d\n", _("bad entry number"), num);
199 vcdinfo_itemid_t itemid;
202 itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
204 p_vcd->i_lsn = vcdinfo_get_entry_lsn(p_obj, num);
205 p_vcd->play_item = itemid;
206 p_vcd->i_track = vcdinfo_get_track(p_obj, num);
207 p_vcd->track_lsn = vcdinfo_get_track_lsn(p_obj, p_vcd->i_track);
208 p_vcd->track_end_lsn = p_vcd->track_lsn +
209 p_vcd->track[p_vcd->i_track-1].size;
211 vcdplayer_set_origin(p_access);
213 dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u\n",
214 p_vcd->i_lsn, p_vcd->track_end_lsn);
219 Set reading to play an segment (e.g. still frame)
222 _vcdplayer_set_segment(access_t * p_access, unsigned int num)
224 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
225 vcdinfo_obj_t *p_obj = p_vcd->vcd;
226 segnum_t num_segs = vcdinfo_get_num_segments(p_obj);
228 if (num >= num_segs) {
229 LOG_ERR("%s %d\n", _("bad segment number"), num);
232 vcdinfo_itemid_t itemid;
234 p_vcd->i_lsn = vcdinfo_get_seg_lsn(p_obj, num);
237 if (VCDINFO_NULL_LSN==p_vcd->i_lsn) {
239 _("Error in getting current segment number"), num);
244 itemid.type = VCDINFO_ITEM_TYPE_SEGMENT;
245 p_vcd->play_item = itemid;
247 vcdplayer_set_origin(p_access);
249 dbg_print(INPUT_DBG_LSN, "LSN: %u\n", p_vcd->i_lsn);
254 /* Play a single item. */
256 vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
258 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
259 vcdinfo_obj_t *p_obj = p_vcd->vcd;
261 dbg_print(INPUT_DBG_CALL, "called itemid.num: %d, itemid.type: %d\n",
262 itemid.num, itemid.type);
266 switch (itemid.type) {
267 case VCDINFO_ITEM_TYPE_SEGMENT:
269 vcdinfo_video_segment_type_t segtype
270 = vcdinfo_get_video_type(p_obj, itemid.num);
271 segnum_t num_segs = vcdinfo_get_num_segments(p_obj);
273 dbg_print(INPUT_DBG_PBC, "%s (%d), itemid.num: %d\n",
274 vcdinfo_video_type2str(p_obj, itemid.num),
275 (int) segtype, itemid.num);
277 if (itemid.num >= num_segs) return;
278 _vcdplayer_set_segment(p_access, itemid.num);
282 case VCDINFO_FILES_VIDEO_NTSC_STILL:
283 case VCDINFO_FILES_VIDEO_NTSC_STILL2:
284 case VCDINFO_FILES_VIDEO_PAL_STILL:
285 case VCDINFO_FILES_VIDEO_PAL_STILL2:
286 p_vcd->in_still = -5;
295 case VCDINFO_ITEM_TYPE_TRACK:
296 dbg_print(INPUT_DBG_PBC, "track %d\n", itemid.num);
297 if (itemid.num < 1 || itemid.num > p_vcd->i_tracks) return;
298 _vcdplayer_set_track(p_access, itemid.num);
301 case VCDINFO_ITEM_TYPE_ENTRY:
303 unsigned int num_entries = vcdinfo_get_num_entries(p_obj);
304 dbg_print(INPUT_DBG_PBC, "entry %d\n", itemid.num);
305 if (itemid.num >= num_entries) return;
306 _vcdplayer_set_entry(p_access, itemid.num);
310 case VCDINFO_ITEM_TYPE_LID:
311 LOG_ERR("%s\n", _("Should have converted p_vcd above"));
314 case VCDINFO_ITEM_TYPE_NOTFOUND:
315 dbg_print(INPUT_DBG_PBC, "play nothing\n");
316 p_vcd->i_lsn = p_vcd->end_lsn;
320 LOG_ERR("item type %d not implemented.\n", itemid.type);
324 p_vcd->play_item = itemid;
326 /* Some players like xine, have a fifo queue of audio and video buffers
327 that need to be flushed when playing a new selection. */
328 /* if (p_vcd->flush_buffers)
329 p_vcd->flush_buffers(); */
333 #endif /* FINISHED */
336 Set's start origin and size for subsequent seeks.
337 input: p_vcd->i_lsn, p_vcd->play_item
338 changed: p_vcd->origin_lsn, p_vcd->end_lsn
341 /* FIXME: add parameters lsn, i_track, p_itemid and set accordingly. */
343 vcdplayer_set_origin(access_t *p_access)
345 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
346 size_t i_size= vcdplayer_get_item_size(p_access, p_vcd->play_item);
348 p_vcd->end_lsn = p_vcd->i_lsn + i_size;
349 p_vcd->origin_lsn = p_vcd->i_lsn;
351 dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN), "end LSN: %u\n", p_vcd->end_lsn);
355 Get the next play-item in the list given in the LIDs. Note play-item
356 here refers to list of play-items for a single LID It shouldn't be
357 confused with a user's list of favorite things to play or the
358 "next" field of a LID which moves us to a different LID.
361 _vcdplayer_inc_play_item(access_t *p_access)
363 vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
366 dbg_print(INPUT_DBG_CALL, "called pli: %d\n", p_vcd->pdi);
368 if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return false;
370 noi = vcdinf_pld_get_noi(p_vcd->pxd.pld);
372 if ( noi <= 0 ) return false;
374 /* Handle delays like autowait or wait here? */
378 if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return false;
381 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld,
383 vcdinfo_itemid_t trans_itemid;
385 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
387 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
388 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s\n",
389 p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num));
390 vcdplayer_play_single_item(p_access, trans_itemid);
395 /* Handles PBC navigation when reaching the end of a play item. */
396 vcdplayer_read_status_t
397 vcdplayer_pbc_nav ( access_t * p_access )
399 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
401 /* We are in playback control. */
402 vcdinfo_itemid_t itemid;
404 /* The end of an entry is really the end of the associated
405 sequence (or track). */
407 if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type) &&
408 (p_vcd->i_lsn < p_vcd->end_lsn) ) {
409 /* Set up to just continue to the next entry */
410 p_vcd->play_item.num++;
411 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
412 "continuing into next entry: %u", p_vcd->play_item.num);
413 VCDPlay( p_access, p_vcd->play_item );
414 /* p_vcd->update_title(); */
418 switch (p_vcd->pxd.descriptor_type) {
419 case PSD_TYPE_END_LIST:
422 case PSD_TYPE_PLAY_LIST: {
423 int wait_time = vcdinf_get_wait_time(p_vcd->pxd.pld);
425 dbg_print(INPUT_DBG_PBC, "playlist wait_time: %d", wait_time);
427 if (vcdplayer_inc_play_item(p_access))
430 /* Handle any wait time given. */
432 if (p_vcd->in_still) {
433 vcdIntfStillTime( p_vcd->p_intf, wait_time );
434 return READ_STILL_FRAME;
438 vcdplayer_update_entry( p_access,
439 vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
440 &itemid.num, "next" );
441 itemid.type = VCDINFO_ITEM_TYPE_LID;
442 VCDPlay( p_access, itemid );
445 case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
446 case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
448 int wait_time = vcdinf_get_timeout_time(p_vcd->pxd.psd);
449 uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcd->pxd.psd);
450 uint16_t max_loop = vcdinf_get_loop_count(p_vcd->pxd.psd);
451 vcdinfo_offset_t *offset_timeout_LID =
452 vcdinfo_get_offset_t(p_vcd->vcd, timeout_offs);
454 dbg_print(INPUT_DBG_PBC, "wait_time: %d, looped: %d, max_loop %d",
455 wait_time, p_vcd->loop_count, max_loop);
457 /* Handle any wait time given */
459 if (p_vcd->in_still) {
460 vcdIntfStillTime( p_vcd->p_intf, wait_time );
461 return READ_STILL_FRAME;
465 /* Handle any looping given. */
466 if ( max_loop == 0 || p_vcd->loop_count < max_loop ) {
468 if (p_vcd->loop_count == 0x7f) p_vcd->loop_count = 0;
469 VCDSeek( p_access, 0 );
470 /* if (p_vcd->in_still) p_vcd->force_redisplay();*/
474 /* Looping finished and wait finished. Move to timeout
475 entry or next entry, or handle still. */
477 if (NULL != offset_timeout_LID) {
478 /* Handle timeout_LID */
479 itemid.num = offset_timeout_LID->lid;
480 itemid.type = VCDINFO_ITEM_TYPE_LID;
481 dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
482 VCDPlay( p_access, itemid );
485 int num_selections = vcdinf_get_num_selections(p_vcd->pxd.psd);
486 if (num_selections > 0) {
487 /* Pick a random selection. */
488 unsigned int bsn=vcdinf_get_bsn(p_vcd->pxd.psd);
489 int rand_selection=bsn +
490 (int) ((num_selections+0.0)*rand()/(RAND_MAX+1.0));
491 lid_t rand_lid=vcdinfo_selection_get_lid (p_vcd->vcd,
494 itemid.num = rand_lid;
495 itemid.type = VCDINFO_ITEM_TYPE_LID;
496 dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
497 rand_selection - bsn, rand_lid);
498 VCDPlay( p_access, itemid );
500 } else if (p_vcd->in_still) {
501 /* Hack: Just go back and do still again */
503 return READ_STILL_FRAME;
508 case VCDINFO_ITEM_TYPE_NOTFOUND:
509 LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
511 case VCDINFO_ITEM_TYPE_SPAREID2:
512 LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
514 case VCDINFO_ITEM_TYPE_LID:
515 LOG_ERR( "LID in PBC -- not supposed to happen" );
521 /* FIXME: Should handle autowait ... */
527 Get the next play-item in the list given in the LIDs. Note play-item
528 here refers to list of play-items for a single LID It shouldn't be
529 confused with a user's list of favorite things to play or the
530 "next" field of a LID which moves us to a different LID.
533 vcdplayer_inc_play_item( access_t *p_access )
535 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
539 dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcd->pdi);
541 if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return VLC_FALSE;
543 noi = vcdinf_pld_get_noi(p_vcd->pxd.pld);
545 if ( noi <= 0 ) return VLC_FALSE;
547 /* Handle delays like autowait or wait here? */
551 if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return VLC_FALSE;
554 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld,
556 vcdinfo_itemid_t trans_itemid;
558 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return VLC_FALSE;
560 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
561 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
562 p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num));
563 return VLC_SUCCESS == VCDPlay( p_access, trans_itemid );
568 Play item assocated with the "default" selection.
570 Return VLC_FALSE if there was some problem.
573 vcdplayer_play_default( access_t * p_access )
575 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
577 vcdinfo_itemid_t itemid;
580 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
586 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
587 "current: %d" , p_vcd->play_item.num);
589 itemid.type = p_vcd->play_item.type;
591 if (vcdplayer_pbc_is_on(p_vcd)) {
593 #if defined(LIBVCD_VERSION)
594 lid_t lid=vcdinfo_get_multi_default_lid(p_vcd->vcd, p_vcd->i_lid,
597 if (VCDINFO_INVALID_LID != lid) {
599 itemid.type = VCDINFO_ITEM_TYPE_LID;
600 dbg_print(INPUT_DBG_PBC, "DEFAULT to %d\n", itemid.num);
602 dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d\n", p_vcd->i_lid);
606 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), p_vcd->i_lid);
608 switch (p_vcd->pxd.descriptor_type) {
609 case PSD_TYPE_SELECTION_LIST:
610 case PSD_TYPE_EXT_SELECTION_LIST:
611 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
612 vcdplayer_update_entry( p_access,
613 vcdinfo_get_default_offset(p_vcd->vcd,
615 &itemid.num, "default");
618 case PSD_TYPE_PLAY_LIST:
619 case PSD_TYPE_END_LIST:
620 case PSD_TYPE_COMMAND_LIST:
621 LOG_WARN( "There is no PBC 'default' selection here" );
624 #endif /* LIBVCD_VERSION (< 0.7.21) */
629 /* PBC is not on. "default" selection beginning of current
632 p_vcd->play_item.num = p_vcd->play_item.num;
636 /** ??? p_vcd->update_title(); ***/
637 return VLC_SUCCESS == VCDPlay( p_access, itemid );
642 Play item assocated with the "next" selection.
644 Return VLC_FALSE if there was some problem.
647 vcdplayer_play_next( access_t * p_access )
649 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
651 vcdinfo_obj_t *p_obj;
652 vcdinfo_itemid_t itemid;
654 if (!p_vcd) return VLC_FALSE;
656 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
657 "current: %d" , p_vcd->play_item.num);
661 itemid.type = p_vcd->play_item.type;
663 if (vcdplayer_pbc_is_on(p_vcd)) {
665 vcdinfo_lid_get_pxd(p_obj, &(p_vcd->pxd), p_vcd->i_lid);
667 switch (p_vcd->pxd.descriptor_type) {
668 case PSD_TYPE_SELECTION_LIST:
669 case PSD_TYPE_EXT_SELECTION_LIST:
670 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
671 vcdplayer_update_entry( p_access,
672 vcdinf_psd_get_next_offset(p_vcd->pxd.psd),
673 &itemid.num, "next");
674 itemid.type = VCDINFO_ITEM_TYPE_LID;
677 case PSD_TYPE_PLAY_LIST:
678 if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
679 vcdplayer_update_entry( p_access,
680 vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
681 &itemid.num, "next");
682 itemid.type = VCDINFO_ITEM_TYPE_LID;
685 case PSD_TYPE_END_LIST:
686 case PSD_TYPE_COMMAND_LIST:
687 LOG_WARN( "There is no PBC 'next' selection here" );
692 /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
696 switch (p_vcd->play_item.type) {
697 case VCDINFO_ITEM_TYPE_ENTRY:
698 case VCDINFO_ITEM_TYPE_SEGMENT:
699 case VCDINFO_ITEM_TYPE_TRACK:
701 switch (p_vcd->play_item.type) {
702 case VCDINFO_ITEM_TYPE_ENTRY:
703 max_entry = p_vcd->i_entries;
705 case VCDINFO_ITEM_TYPE_SEGMENT:
706 max_entry = p_vcd->i_segments;
708 case VCDINFO_ITEM_TYPE_TRACK:
709 max_entry = p_vcd->i_tracks;
711 default: ; /* Handle exceptional cases below */
714 if (p_vcd->play_item.num+1 < max_entry) {
715 itemid.num = p_vcd->play_item.num+1;
717 LOG_WARN( "At the end - non-PBC 'next' not possible here" );
723 case VCDINFO_ITEM_TYPE_LID:
725 /* Should have handled above. */
726 LOG_WARN( "Internal inconsistency - should not have gotten here." );
734 /** ??? p_vcd->update_title(); ***/
735 return VLC_SUCCESS == VCDPlay( p_access, itemid );
740 Play item assocated with the "prev" selection.
742 Return VLC_FALSE if there was some problem.
745 vcdplayer_play_prev( access_t * p_access )
747 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
748 vcdinfo_obj_t *p_obj = p_vcd->vcd;
749 vcdinfo_itemid_t itemid;
751 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
752 "current: %d" , p_vcd->play_item.num);
754 itemid.type = p_vcd->play_item.type;
756 if (vcdplayer_pbc_is_on(p_vcd)) {
758 vcdinfo_lid_get_pxd(p_obj, &(p_vcd->pxd), p_vcd->i_lid);
760 switch (p_vcd->pxd.descriptor_type) {
761 case PSD_TYPE_SELECTION_LIST:
762 case PSD_TYPE_EXT_SELECTION_LIST:
763 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
764 vcdplayer_update_entry( p_access,
765 vcdinf_psd_get_prev_offset(p_vcd->pxd.psd),
766 &itemid.num, "prev");
767 itemid.type = VCDINFO_ITEM_TYPE_LID;
770 case PSD_TYPE_PLAY_LIST:
771 if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
772 vcdplayer_update_entry( p_access,
773 vcdinf_pld_get_prev_offset(p_vcd->pxd.pld),
774 &itemid.num, "prev");
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 'prev' selection here" );
785 /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
787 int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type)
790 if (p_vcd->play_item.num > min_entry) {
791 itemid.num = p_vcd->play_item.num-1;
793 LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
799 /** ??? p_vcd->update_title(); ***/
800 return VLC_SUCCESS == VCDPlay( p_access, itemid );
805 Play item assocated with the "return" selection.
807 Return VLC_FALSE if there was some problem.
810 vcdplayer_play_return( access_t * p_access )
812 vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
813 vcdinfo_obj_t *p_obj = p_vcd->vcd;
814 vcdinfo_itemid_t itemid;
816 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
817 "current: %d" , p_vcd->play_item.num);
819 itemid.type = p_vcd->play_item.type;
821 if (vcdplayer_pbc_is_on(p_vcd)) {
823 vcdinfo_lid_get_pxd(p_obj, &(p_vcd->pxd), p_vcd->i_lid);
825 switch (p_vcd->pxd.descriptor_type) {
826 case PSD_TYPE_SELECTION_LIST:
827 case PSD_TYPE_EXT_SELECTION_LIST:
828 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
829 vcdplayer_update_entry( p_access,
830 vcdinf_psd_get_return_offset(p_vcd->pxd.psd),
831 &itemid.num, "return");
832 itemid.type = VCDINFO_ITEM_TYPE_LID;
835 case PSD_TYPE_PLAY_LIST:
836 if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
837 vcdplayer_update_entry( p_access,
838 vcdinf_pld_get_return_offset(p_vcd->pxd.pld),
839 &itemid.num, "return");
840 itemid.type = VCDINFO_ITEM_TYPE_LID;
843 case PSD_TYPE_END_LIST:
844 case PSD_TYPE_COMMAND_LIST:
845 LOG_WARN( "There is no PBC 'return' selection here" );
850 /* PBC is not on. "Return" selection is min_entry if possible. */
852 p_vcd->play_item.num = (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type)
857 /** ??? p_vcd->update_title(); ***/
858 return VLC_SUCCESS == VCDPlay( p_access, itemid );