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 access_vcd_data_t *p_vcd )
56 return VCDINFO_INVALID_ENTRY != p_vcd->i_lid;
60 vcdplayer_update_entry( access_t * p_access, uint16_t ofs,
61 uint16_t *entry, const char *label)
63 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
65 if ( ofs == VCDINFO_INVALID_OFFSET ) {
66 *entry = VCDINFO_INVALID_ENTRY;
68 vcdinfo_offset_t *off = vcdinfo_get_offset_t(p_vcd->vcd, ofs);
71 dbg_print(INPUT_DBG_PBC, "%s: LID %d\n", label, off->lid);
73 *entry = VCDINFO_INVALID_ENTRY;
77 /* Handles navigation when NOT in PBC reaching the end of a play item.
79 The navigations rules here may be sort of made up, but the intent
80 is to do something that's probably right or helpful.
82 return VLC_TRUE if the caller should return.
84 vcdplayer_read_status_t
85 vcdplayer_non_pbc_nav ( access_t * p_access )
87 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
89 /* Not in playback control. Do we advance automatically or stop? */
90 switch (p_vcd->play_item.type) {
91 case VCDINFO_ITEM_TYPE_TRACK:
92 case VCDINFO_ITEM_TYPE_ENTRY: {
94 dbg_print( INPUT_DBG_LSN, "new track %d, lsn %d", p_vcd->i_track+1,
95 vcdinfo_get_track_lsn(p_vcd->vcd, p_vcd->i_track+1) );
99 case VCDINFO_ITEM_TYPE_SPAREID2:
100 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
105 return READ_STILL_FRAME ;
108 case VCDINFO_ITEM_TYPE_NOTFOUND:
109 LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen");
111 case VCDINFO_ITEM_TYPE_LID:
112 LOG_ERR ("LID outside PBC -- not supposed to happen");
114 case VCDINFO_ITEM_TYPE_SEGMENT:
115 /* Hack: Just go back and do still again */
119 dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
120 "End of Segment - looping" );
121 return READ_STILL_FRAME;
128 /* Handles PBC navigation when reaching the end of a play item. */
129 vcdplayer_read_status_t
130 vcdplayer_pbc_nav ( access_t * p_access )
132 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
134 /* We are in playback control. */
135 vcdinfo_itemid_t itemid;
137 /* The end of an entry is really the end of the associated
138 sequence (or track). */
140 if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type) &&
141 (p_vcd->i_lsn < p_vcd->end_lsn) ) {
142 /* Set up to just continue to the next entry */
143 p_vcd->play_item.num++;
144 dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
145 "continuing into next entry: %u", p_vcd->play_item.num);
146 VCDPlay( p_access, p_vcd->play_item );
147 /* p_vcd->update_title(); */
151 switch (p_vcd->pxd.descriptor_type) {
152 case PSD_TYPE_END_LIST:
155 case PSD_TYPE_PLAY_LIST: {
156 int wait_time = vcdinf_get_wait_time(p_vcd->pxd.pld);
158 dbg_print(INPUT_DBG_PBC, "playlist wait_time: %d", wait_time);
160 if (vcdplayer_inc_play_item(p_access))
163 /* Handle any wait time given. */
165 if (p_vcd->in_still) {
166 vcdIntfStillTime( p_vcd->p_intf, wait_time );
167 return READ_STILL_FRAME;
171 vcdplayer_update_entry( p_access,
172 vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
173 &itemid.num, "next" );
174 itemid.type = VCDINFO_ITEM_TYPE_LID;
175 VCDPlay( p_access, itemid );
178 case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
179 case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
181 int wait_time = vcdinf_get_timeout_time(p_vcd->pxd.psd);
182 uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcd->pxd.psd);
183 uint16_t max_loop = vcdinf_get_loop_count(p_vcd->pxd.psd);
184 vcdinfo_offset_t *offset_timeout_LID =
185 vcdinfo_get_offset_t(p_vcd->vcd, timeout_offs);
187 dbg_print(INPUT_DBG_PBC, "wait_time: %d, looped: %d, max_loop %d",
188 wait_time, p_vcd->loop_count, max_loop);
190 /* Handle any wait time given */
192 if (p_vcd->in_still) {
193 vcdIntfStillTime( p_vcd->p_intf, wait_time );
194 return READ_STILL_FRAME;
198 /* Handle any looping given. */
199 if ( max_loop == 0 || p_vcd->loop_count < max_loop ) {
201 if (p_vcd->loop_count == 0x7f) p_vcd->loop_count = 0;
202 VCDSeek( p_access, 0 );
203 /* if (p_vcd->in_still) p_vcd->force_redisplay();*/
207 /* Looping finished and wait finished. Move to timeout
208 entry or next entry, or handle still. */
210 if (NULL != offset_timeout_LID) {
211 /* Handle timeout_LID */
212 itemid.num = offset_timeout_LID->lid;
213 itemid.type = VCDINFO_ITEM_TYPE_LID;
214 dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
215 VCDPlay( p_access, itemid );
218 int num_selections = vcdinf_get_num_selections(p_vcd->pxd.psd);
219 if (num_selections > 0) {
220 /* Pick a random selection. */
221 unsigned int bsn=vcdinf_get_bsn(p_vcd->pxd.psd);
222 int rand_selection=bsn +
223 (int) ((num_selections+0.0)*rand()/(RAND_MAX+1.0));
224 lid_t rand_lid=vcdinfo_selection_get_lid (p_vcd->vcd,
227 itemid.num = rand_lid;
228 itemid.type = VCDINFO_ITEM_TYPE_LID;
229 dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
230 rand_selection - bsn, rand_lid);
231 VCDPlay( p_access, itemid );
233 } else if (p_vcd->in_still) {
234 /* Hack: Just go back and do still again */
236 return READ_STILL_FRAME;
241 case VCDINFO_ITEM_TYPE_NOTFOUND:
242 LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
244 case VCDINFO_ITEM_TYPE_SPAREID2:
245 LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
247 case VCDINFO_ITEM_TYPE_LID:
248 LOG_ERR( "LID in PBC -- not supposed to happen" );
254 /* FIXME: Should handle autowait ... */
260 Get the next play-item in the list given in the LIDs. Note play-item
261 here refers to list of play-items for a single LID It shouldn't be
262 confused with a user's list of favorite things to play or the
263 "next" field of a LID which moves us to a different LID.
266 vcdplayer_inc_play_item( access_t *p_access )
268 access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
272 dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcd->pdi);
274 if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return VLC_FALSE;
276 noi = vcdinf_pld_get_noi(p_vcd->pxd.pld);
278 if ( noi <= 0 ) return VLC_FALSE;
280 /* Handle delays like autowait or wait here? */
284 if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return VLC_FALSE;
287 uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld,
289 vcdinfo_itemid_t trans_itemid;
291 if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return VLC_FALSE;
293 vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
294 dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
295 p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num));
296 return VLC_SUCCESS == VCDPlay( p_access, trans_itemid );
301 Play item assocated with the "default" selection.
303 Return VLC_FALSE if there was some problem.
306 vcdplayer_play_default( access_t * p_access )
308 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
310 vcdinfo_itemid_t itemid;
313 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
319 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
320 "current: %d" , p_vcd->play_item.num);
322 itemid.type = p_vcd->play_item.type;
324 if (vcdplayer_pbc_is_on(p_vcd)) {
326 #if defined(LIBVCD_VERSION)
327 lid_t lid=vcdinfo_get_multi_default_lid(p_vcd->vcd, p_vcd->i_lid,
330 if (VCDINFO_INVALID_LID != lid) {
332 itemid.type = VCDINFO_ITEM_TYPE_LID;
333 dbg_print(INPUT_DBG_PBC, "DEFAULT to %d\n", itemid.num);
335 dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d\n", p_vcd->i_lid);
339 vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), p_vcd->i_lid);
341 switch (p_vcd->pxd.descriptor_type) {
342 case PSD_TYPE_SELECTION_LIST:
343 case PSD_TYPE_EXT_SELECTION_LIST:
344 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
345 vcdplayer_update_entry( p_access,
346 vcdinfo_get_default_offset(p_vcd->vcd,
348 &itemid.num, "default");
351 case PSD_TYPE_PLAY_LIST:
352 case PSD_TYPE_END_LIST:
353 case PSD_TYPE_COMMAND_LIST:
354 LOG_WARN( "There is no PBC 'default' selection here" );
357 #endif /* LIBVCD_VERSION (< 0.7.21) */
362 /* PBC is not on. "default" selection beginning of current
365 p_vcd->play_item.num = p_vcd->play_item.num;
369 /** ??? p_vcd->update_title(); ***/
370 return VLC_SUCCESS == VCDPlay( p_access, itemid );
375 Play item assocated with the "next" selection.
377 Return VLC_FALSE if there was some problem.
380 vcdplayer_play_next( access_t * p_access )
382 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
385 vcdinfo_itemid_t itemid;
387 if (!p_vcd) return VLC_FALSE;
389 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
390 "current: %d" , p_vcd->play_item.num);
394 itemid.type = p_vcd->play_item.type;
396 if (vcdplayer_pbc_is_on(p_vcd)) {
398 vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), p_vcd->i_lid);
400 switch (p_vcd->pxd.descriptor_type) {
401 case PSD_TYPE_SELECTION_LIST:
402 case PSD_TYPE_EXT_SELECTION_LIST:
403 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
404 vcdplayer_update_entry( p_access,
405 vcdinf_psd_get_next_offset(p_vcd->pxd.psd),
406 &itemid.num, "next");
407 itemid.type = VCDINFO_ITEM_TYPE_LID;
410 case PSD_TYPE_PLAY_LIST:
411 if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
412 vcdplayer_update_entry( p_access,
413 vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
414 &itemid.num, "next");
415 itemid.type = VCDINFO_ITEM_TYPE_LID;
418 case PSD_TYPE_END_LIST:
419 case PSD_TYPE_COMMAND_LIST:
420 LOG_WARN( "There is no PBC 'next' selection here" );
425 /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
429 switch (p_vcd->play_item.type) {
430 case VCDINFO_ITEM_TYPE_ENTRY:
431 case VCDINFO_ITEM_TYPE_SEGMENT:
432 case VCDINFO_ITEM_TYPE_TRACK:
434 switch (p_vcd->play_item.type) {
435 case VCDINFO_ITEM_TYPE_ENTRY:
436 max_entry = p_vcd->i_entries;
438 case VCDINFO_ITEM_TYPE_SEGMENT:
439 max_entry = p_vcd->i_segments;
441 case VCDINFO_ITEM_TYPE_TRACK:
442 max_entry = p_vcd->i_tracks;
444 default: ; /* Handle exceptional cases below */
447 if (p_vcd->play_item.num+1 < max_entry) {
448 itemid.num = p_vcd->play_item.num+1;
450 LOG_WARN( "At the end - non-PBC 'next' not possible here" );
456 case VCDINFO_ITEM_TYPE_LID:
458 /* Should have handled above. */
459 LOG_WARN( "Internal inconsistency - should not have gotten here." );
467 /** ??? p_vcd->update_title(); ***/
468 return VLC_SUCCESS == VCDPlay( p_access, itemid );
473 Play item assocated with the "prev" selection.
475 Return VLC_FALSE if there was some problem.
478 vcdplayer_play_prev( access_t * p_access )
480 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
482 vcdinfo_obj_t *obj = p_vcd->vcd;
483 vcdinfo_itemid_t itemid;
485 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
486 "current: %d" , p_vcd->play_item.num);
488 itemid.type = p_vcd->play_item.type;
490 if (vcdplayer_pbc_is_on(p_vcd)) {
492 vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), p_vcd->i_lid);
494 switch (p_vcd->pxd.descriptor_type) {
495 case PSD_TYPE_SELECTION_LIST:
496 case PSD_TYPE_EXT_SELECTION_LIST:
497 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
498 vcdplayer_update_entry( p_access,
499 vcdinf_psd_get_prev_offset(p_vcd->pxd.psd),
500 &itemid.num, "prev");
501 itemid.type = VCDINFO_ITEM_TYPE_LID;
504 case PSD_TYPE_PLAY_LIST:
505 if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
506 vcdplayer_update_entry( p_access,
507 vcdinf_pld_get_prev_offset(p_vcd->pxd.pld),
508 &itemid.num, "prev");
509 itemid.type = VCDINFO_ITEM_TYPE_LID;
512 case PSD_TYPE_END_LIST:
513 case PSD_TYPE_COMMAND_LIST:
514 LOG_WARN( "There is no PBC 'prev' selection here" );
519 /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
521 int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type)
524 if (p_vcd->play_item.num > min_entry) {
525 itemid.num = p_vcd->play_item.num-1;
527 LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
533 /** ??? p_vcd->update_title(); ***/
534 return VLC_SUCCESS == VCDPlay( p_access, itemid );
539 Play item assocated with the "return" selection.
541 Return VLC_FALSE if there was some problem.
544 vcdplayer_play_return( access_t * p_access )
546 access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
548 vcdinfo_obj_t *obj = p_vcd->vcd;
549 vcdinfo_itemid_t itemid;
551 dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
552 "current: %d" , p_vcd->play_item.num);
554 itemid.type = p_vcd->play_item.type;
556 if (vcdplayer_pbc_is_on(p_vcd)) {
558 vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), p_vcd->i_lid);
560 switch (p_vcd->pxd.descriptor_type) {
561 case PSD_TYPE_SELECTION_LIST:
562 case PSD_TYPE_EXT_SELECTION_LIST:
563 if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
564 vcdplayer_update_entry( p_access,
565 vcdinf_psd_get_return_offset(p_vcd->pxd.psd),
566 &itemid.num, "return");
567 itemid.type = VCDINFO_ITEM_TYPE_LID;
570 case PSD_TYPE_PLAY_LIST:
571 if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
572 vcdplayer_update_entry( p_access,
573 vcdinf_pld_get_return_offset(p_vcd->pxd.pld),
574 &itemid.num, "return");
575 itemid.type = VCDINFO_ITEM_TYPE_LID;
578 case PSD_TYPE_END_LIST:
579 case PSD_TYPE_COMMAND_LIST:
580 LOG_WARN( "There is no PBC 'return' selection here" );
585 /* PBC is not on. "Return" selection is min_entry if possible. */
587 p_vcd->play_item.num = (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type)
592 /** ??? p_vcd->update_title(); ***/
593 return VLC_SUCCESS == VCDPlay( p_access, itemid );