]> git.sesse.net Git - vlc/blob - modules/access/vcdx/vcdplayer.c
Merge branch 'master' into lpcm_encoder
[vlc] / modules / access / vcdx / vcdplayer.c
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>
6  * $Id$
7  *
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.
12  *
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.
17  *
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  *****************************************************************************/
22
23 /*
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.
27  */
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <vlc_common.h>
37 #include <vlc_input.h>
38 #include <vlc_interface.h>
39 #include <vlc_rand.h>
40
41 #include "vcd.h"
42 #include "vcdplayer.h"
43 #include "access.h"
44
45 #include <cdio/cdio.h>
46 #include <cdio/util.h>
47 #include <libvcd/info.h>
48
49 /*!
50   Return true if playback control (PBC) is on
51 */
52 bool
53 vcdplayer_pbc_is_on( const vcdplayer_t *p_vcdplayer )
54 {
55   return VCDINFO_INVALID_ENTRY != p_vcdplayer->i_lid;
56 }
57
58 /* Given an itemid, return the size for the object (via information
59    previously stored when opening the vcd). */
60 static size_t
61 vcdplayer_get_item_size(access_t * p_access, vcdinfo_itemid_t itemid)
62 {
63   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
64
65   switch (itemid.type) {
66   case VCDINFO_ITEM_TYPE_ENTRY:
67     return p_vcdplayer->entry[itemid.num].size;
68     break;
69   case VCDINFO_ITEM_TYPE_SEGMENT:
70     return p_vcdplayer->segment[itemid.num].size;
71     break;
72   case VCDINFO_ITEM_TYPE_TRACK:
73     return p_vcdplayer->track[itemid.num-1].size;
74     break;
75   case VCDINFO_ITEM_TYPE_LID:
76     /* Play list number (LID) */
77     return 0;
78     break;
79   case VCDINFO_ITEM_TYPE_NOTFOUND:
80   case VCDINFO_ITEM_TYPE_SPAREID2:
81   default:
82     LOG_ERR("%s %d", "bad item type", itemid.type);
83     return 0;
84   }
85 }
86
87 static void
88 vcdplayer_update_entry( access_t * p_access, uint16_t ofs,
89                         uint16_t *entry, const char *label)
90 {
91   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
92
93   if ( ofs == VCDINFO_INVALID_OFFSET ) {
94     *entry = VCDINFO_INVALID_ENTRY;
95   } else {
96     vcdinfo_offset_t *off = vcdinfo_get_offset_t(p_vcdplayer->vcd, ofs);
97     if (off != NULL) {
98       *entry = off->lid;
99       dbg_print(INPUT_DBG_PBC, "%s: LID %d", label, off->lid);
100     } else
101       *entry = VCDINFO_INVALID_ENTRY;
102   }
103 }
104
105 /* Handles navigation when NOT in PBC reaching the end of a play item.
106
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.
109
110    return true if the caller should return.
111 */
112 static vcdplayer_read_status_t
113 vcdplayer_non_pbc_nav ( access_t *p_access, uint8_t *wait_time )
114 {
115   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
116
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 ) )
122       return READ_END;
123     break;
124   }
125   case VCDINFO_ITEM_TYPE_SPAREID2:
126     dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
127                "SPAREID2" );
128     if (p_vcdplayer->in_still)
129     {
130       dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
131                  "End of still spareid2" );
132       *wait_time = 255;
133       return READ_STILL_FRAME ;
134     }
135     return READ_END;
136   case VCDINFO_ITEM_TYPE_NOTFOUND:
137     LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen");
138     return READ_ERROR;
139   case VCDINFO_ITEM_TYPE_LID:
140     LOG_ERR ("LID outside PBC -- not supposed to happen");
141     return READ_ERROR;
142   case VCDINFO_ITEM_TYPE_SEGMENT:
143       /* Hack: Just go back and do still again */
144     /* FIXME */
145     if (p_vcdplayer->in_still)
146     {
147       dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
148                  "End of still Segment" );
149       *wait_time = 10;
150       return READ_STILL_FRAME;
151     }
152     return READ_END;
153   }
154   return READ_BLOCK;
155 }
156
157 /*!
158   Set reading to play an entire track.
159 */
160 static void
161 _vcdplayer_set_track(access_t * p_access, track_t i_track)
162 {
163   vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
164   if (i_track < 1 || i_track > p_vcdplayer->i_tracks)
165     return;
166   else {
167     const vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
168     vcdinfo_itemid_t itemid;
169
170     itemid.num             = i_track;
171     itemid.type            = VCDINFO_ITEM_TYPE_TRACK;
172     p_vcdplayer->in_still  = 0;
173
174     VCDSetOrigin(p_access, vcdinfo_get_track_lsn(p_vcdinfo, i_track),
175          i_track, &itemid);
176
177     dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
178   }
179 }
180
181 /*!
182   Set reading to play an entry
183 */
184 static void
185 _vcdplayer_set_entry(access_t * p_access, unsigned int num)
186 {
187   vcdplayer_t   *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
188   vcdinfo_obj_t *p_vcdinfo   = p_vcdplayer->vcd;
189   const unsigned int   i_entries = vcdinfo_get_num_entries(p_vcdinfo);
190
191   if (num >= i_entries) {
192     LOG_ERR("%s %d", "bad entry number", num);
193     return;
194   } else {
195     vcdinfo_itemid_t itemid;
196
197     itemid.num            = num;
198     itemid.type           = VCDINFO_ITEM_TYPE_ENTRY;
199     p_vcdplayer->i_still  = 0;
200
201     VCDSetOrigin(p_access, vcdinfo_get_entry_lsn(p_vcdinfo, num),
202         vcdinfo_get_track(p_vcdinfo, num), &itemid);
203
204     dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u",
205               p_vcdplayer->i_lsn, p_vcdplayer->track_end_lsn);
206   }
207 }
208
209 /*!
210   Set reading to play an segment (e.g. still frame)
211 */
212 static void
213 _vcdplayer_set_segment(access_t * p_access, unsigned int num)
214 {
215   vcdplayer_t   *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
216   vcdinfo_obj_t *p_vcdinfo   = p_vcdplayer->vcd;
217   segnum_t       i_segs    = vcdinfo_get_num_segments(p_vcdinfo);
218
219   if (num >= i_segs) {
220     LOG_ERR("%s %d", "bad segment number", num);
221     return;
222   } else {
223     vcdinfo_itemid_t itemid;
224
225     if (VCDINFO_NULL_LSN==p_vcdplayer->i_lsn) {
226       LOG_ERR("%s %d",
227               "Error in getting current segment number", num);
228       return;
229     }
230  
231     itemid.num = num;
232     itemid.type = VCDINFO_ITEM_TYPE_SEGMENT;
233
234     VCDSetOrigin(p_access, vcdinfo_get_seg_lsn(p_vcdinfo, num), 0, &itemid);
235  
236     dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
237   }
238 }
239
240 /* Play entry. */
241 /* Play a single item. */
242 static bool
243 vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
244 {
245   vcdplayer_t   *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
246   vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
247
248   dbg_print(INPUT_DBG_CALL, "called itemid.num: %d, itemid.type: %d",
249             itemid.num, itemid.type);
250
251   p_vcdplayer->i_still = 0;
252
253   switch (itemid.type) {
254   case VCDINFO_ITEM_TYPE_SEGMENT:
255     {
256       vcdinfo_video_segment_type_t segtype
257         = vcdinfo_get_video_type(p_vcdinfo, itemid.num);
258       segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
259
260       dbg_print(INPUT_DBG_PBC, "%s (%d), itemid.num: %d",
261                 vcdinfo_video_type2str(p_vcdinfo, itemid.num),
262                 (int) segtype, itemid.num);
263
264       if (itemid.num >= i_segs) return false;
265       _vcdplayer_set_segment(p_access, itemid.num);
266  
267       switch (segtype)
268         {
269         case VCDINFO_FILES_VIDEO_NTSC_STILL:
270         case VCDINFO_FILES_VIDEO_NTSC_STILL2:
271         case VCDINFO_FILES_VIDEO_PAL_STILL:
272         case VCDINFO_FILES_VIDEO_PAL_STILL2:
273           p_vcdplayer->i_still = STILL_READING;
274           break;
275         default:
276           p_vcdplayer->i_still = 0;
277         }
278  
279       break;
280     }
281  
282   case VCDINFO_ITEM_TYPE_TRACK:
283     dbg_print(INPUT_DBG_PBC, "track %d", itemid.num);
284     if (itemid.num < 1 || itemid.num > p_vcdplayer->i_tracks) return false;
285     _vcdplayer_set_track(p_access, itemid.num);
286     break;
287  
288   case VCDINFO_ITEM_TYPE_ENTRY:
289     {
290       unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
291       dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num);
292       if (itemid.num >= i_entries) return false;
293       _vcdplayer_set_entry(p_access, itemid.num);
294       break;
295     }
296  
297   case VCDINFO_ITEM_TYPE_LID:
298     LOG_ERR("%s", "Should have converted p_vcdplayer above");
299     return false;
300     break;
301
302   case VCDINFO_ITEM_TYPE_NOTFOUND:
303     dbg_print(INPUT_DBG_PBC, "play nothing");
304     p_vcdplayer->i_lsn = p_vcdplayer->end_lsn;
305     return false;
306
307   default:
308     LOG_ERR("item type %d not implemented.", itemid.type);
309     return false;
310   }
311  
312   p_vcdplayer->play_item = itemid;
313
314   /* Some players like xine, have a fifo queue of audio and video buffers
315      that need to be flushed when playing a new selection. */
316   /*  if (p_vcdplayer->flush_buffers)
317       p_vcdplayer->flush_buffers(); */
318   return true;
319 }
320
321 /*
322    Set's start origin and size for subsequent seeks.
323    input: p_vcdplayer->i_lsn, p_vcdplayer->play_item
324    changed: p_vcdplayer->origin_lsn, p_vcdplayer->end_lsn
325 */
326
327 void
328 vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track,
329              const vcdinfo_itemid_t *p_itemid)
330 {
331   vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
332   const size_t i_size= vcdplayer_get_item_size(p_access, *p_itemid);
333
334   if( VCDINFO_NULL_LSN == i_lsn )
335   {
336     LOG_ERR("%s %d", "Invalid LSN for track", i_track);
337     return;
338   }
339
340   p_vcdplayer->play_item.num  = p_itemid->num;
341   p_vcdplayer->play_item.type = p_itemid->type;
342   p_vcdplayer->i_lsn          = i_lsn;
343   p_vcdplayer->end_lsn        = p_vcdplayer->i_lsn + i_size;
344   p_vcdplayer->origin_lsn     = p_vcdplayer->i_lsn;
345   p_vcdplayer->i_track        = i_track;
346   p_vcdplayer->track_lsn      = vcdinfo_get_track_lsn(p_vcdplayer->vcd,
347                               i_track);
348   p_vcdplayer->track_end_lsn  = p_vcdplayer->track_lsn +
349     vcdinfo_get_track_sect_count(p_vcdplayer->vcd, i_track);
350
351   dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN),
352         "lsn %u, end LSN: %u item.num %d, item.type %d",
353         p_vcdplayer->i_lsn, p_vcdplayer->end_lsn,
354         p_vcdplayer->play_item.num, p_vcdplayer->play_item.type);
355 }
356
357 /*!
358   Get the next play-item in the list given in the LIDs. Note play-item
359   here refers to list of play-items for a single LID It shouldn't be
360   confused with a user's list of favorite things to play or the
361   "next" field of a LID which moves us to a different LID.
362  */
363 static bool
364 vcdplayer_inc_play_item(access_t *p_access)
365 {
366   vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
367   int noi;
368
369   dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcdplayer->pdi);
370
371   if ( NULL == p_vcdplayer || NULL == p_vcdplayer->pxd.pld  )
372     return false;
373
374   noi = vcdinf_pld_get_noi(p_vcdplayer->pxd.pld);
375   if ( noi <= 0 )
376     return false;
377  
378   /* Handle delays like autowait or wait here? */
379
380   p_vcdplayer->pdi++;
381
382   if ( p_vcdplayer->pdi < 0 || p_vcdplayer->pdi >= noi )
383     return false;
384
385   uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcdplayer->pxd.pld,
386                                                      p_vcdplayer->pdi);
387   vcdinfo_itemid_t trans_itemid;
388
389   if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
390  
391   vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
392   dbg_print(INPUT_DBG_PBC, "  play-item[%d]: %s",
393             p_vcdplayer->pdi, vcdinfo_pin2str (trans_itemid_num));
394   return vcdplayer_play_single_item(p_access, trans_itemid);
395 }
396
397 void
398 vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid)
399 {
400   vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
401
402   dbg_print(INPUT_DBG_CALL, "called itemid.num: %d itemid.type: %d",
403             itemid.num, itemid.type);
404
405   if  (!vcdplayer_pbc_is_on(p_vcdplayer)) {
406     vcdplayer_play_single_item(p_access, itemid);
407   } else {
408     /* PBC on - Itemid.num is LID. */
409
410     vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
411
412     if (p_vcdinfo == NULL)
413       return;
414
415     p_vcdplayer->i_lid = itemid.num;
416     vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), itemid.num);
417  
418     switch (p_vcdplayer->pxd.descriptor_type) {
419  
420     case PSD_TYPE_SELECTION_LIST:
421     case PSD_TYPE_EXT_SELECTION_LIST: {
422       vcdinfo_itemid_t trans_itemid;
423       uint16_t trans_itemid_num;
424
425       if (p_vcdplayer->pxd.psd == NULL) return;
426       trans_itemid_num  = vcdinf_psd_get_itemid(p_vcdplayer->pxd.psd);
427       vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
428       p_vcdplayer->i_loop     = 1;
429       p_vcdplayer->loop_item  = trans_itemid;
430       vcdplayer_play_single_item(p_access, trans_itemid);
431       break;
432     }
433  
434     case PSD_TYPE_PLAY_LIST: {
435       if (p_vcdplayer->pxd.pld == NULL) return;
436       p_vcdplayer->pdi = -1;
437       vcdplayer_inc_play_item(p_access);
438       break;
439     }
440  
441     case PSD_TYPE_END_LIST:
442     case PSD_TYPE_COMMAND_LIST:
443  
444     default:
445       ;
446     }
447   }
448 }
449
450 /* Handles PBC navigation when reaching the end of a play item. */
451 static vcdplayer_read_status_t
452 vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time )
453 {
454   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
455
456   /* We are in playback control. */
457   vcdinfo_itemid_t itemid;
458
459   /* The end of an entry is really the end of the associated
460      sequence (or track). */
461  
462   if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) &&
463        (p_vcdplayer->i_lsn < p_vcdplayer->end_lsn) ) {
464     /* Set up to just continue to the next entry */
465     p_vcdplayer->play_item.num++;
466     dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
467                "continuing into next entry: %u", p_vcdplayer->play_item.num);
468     vcdplayer_play_single_item( p_access, p_vcdplayer->play_item );
469     /* p_vcdplayer->update_title(); */
470     return READ_BLOCK;
471   }
472  
473   switch (p_vcdplayer->pxd.descriptor_type) {
474   case PSD_TYPE_END_LIST:
475     return READ_END;
476     break;
477   case PSD_TYPE_PLAY_LIST: {
478     if (vcdplayer_inc_play_item(p_access))
479       return READ_BLOCK;
480
481     /* Set up for caller process wait time given. */
482     if (p_vcdplayer->i_still) {
483       *wait_time = vcdinf_get_wait_time(p_vcdplayer->pxd.pld);
484       dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
485         "playlist wait time: %d", *wait_time);
486       return READ_STILL_FRAME;
487     }
488
489     /* Wait time has been processed; continue with next entry. */
490     vcdplayer_update_entry( p_access,
491                             vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
492                             &itemid.num, "next" );
493     itemid.type = VCDINFO_ITEM_TYPE_LID;
494     vcdplayer_play( p_access, itemid );
495     break;
496   }
497   case PSD_TYPE_SELECTION_LIST:     /* Selection List (+Ext. for SVCD) */
498   case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
499     {
500       uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcdplayer->pxd.psd);
501       uint16_t max_loop     = vcdinf_get_loop_count(p_vcdplayer->pxd.psd);
502       vcdinfo_offset_t *offset_timeout_LID =
503         vcdinfo_get_offset_t(p_vcdplayer->vcd, timeout_offs);
504  
505       dbg_print(INPUT_DBG_PBC, "looped: %d, max_loop %d",
506                 p_vcdplayer->i_loop, max_loop);
507  
508       /* Set up for caller process wait time given. */
509       if (p_vcdplayer->i_still) {
510         *wait_time = vcdinf_get_timeout_time(p_vcdplayer->pxd.psd);
511         dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
512                   "playlist wait_time: %d", *wait_time);
513         return READ_STILL_FRAME;
514       }
515  
516       /* Wait time has been processed; continue with next entry. */
517       /* Handle any looping given. */
518       if ( max_loop == 0 || p_vcdplayer->i_loop < max_loop ) {
519         p_vcdplayer->i_loop++;
520         if (p_vcdplayer->i_loop == 0x7f) p_vcdplayer->i_loop = 0;
521         vcdplayer_play_single_item(p_access, p_vcdplayer->loop_item);
522         /* if (p_vcdplayer->i_still) p_vcdplayer->force_redisplay();*/
523         return READ_BLOCK;
524       }
525  
526       /* Looping finished and wait finished. Move to timeout
527          entry or next entry, or handle still. */
528  
529       if (NULL != offset_timeout_LID) {
530         /* Handle timeout_LID */
531         itemid.num  = offset_timeout_LID->lid;
532         itemid.type = VCDINFO_ITEM_TYPE_LID;
533         dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
534         vcdplayer_play( p_access, itemid );
535         return READ_BLOCK;
536       } else {
537         int i_selections = vcdinf_get_num_selections(p_vcdplayer->pxd.psd);
538         if (i_selections > 0) {
539           /* Pick a random selection. */
540           unsigned int bsn=vcdinf_get_bsn(p_vcdplayer->pxd.psd);
541           int rand_selection=bsn +
542             ((unsigned)vlc_lrand48() % (unsigned)i_selections);
543           lid_t rand_lid=vcdinfo_selection_get_lid (p_vcdplayer->vcd,
544                             p_vcdplayer->i_lid,
545                             rand_selection);
546           itemid.num = rand_lid;
547           itemid.type = VCDINFO_ITEM_TYPE_LID;
548           dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
549                     rand_selection - bsn, rand_lid);
550           vcdplayer_play( p_access, itemid );
551           return READ_BLOCK;
552         } else if (p_vcdplayer->i_still) {
553           /* Hack: Just go back and do still again */
554           msleep(10000);
555           return READ_STILL_FRAME;
556         }
557       }
558       break;
559     }
560   case VCDINFO_ITEM_TYPE_NOTFOUND:
561     LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
562     break;
563   case VCDINFO_ITEM_TYPE_SPAREID2:
564     LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
565     break;
566   case VCDINFO_ITEM_TYPE_LID:
567     LOG_ERR( "LID in PBC -- not supposed to happen" );
568     break;
569  
570   default:
571     ;
572   }
573   /* FIXME: Should handle autowait ...  */
574
575   return READ_ERROR;
576 }
577
578 /*!
579   Read block into p_buf and return the status back.
580
581   This routine is a bit complicated because on reaching the end of
582   a track or entry we may automatically advance to the item, or
583   interpret the next item in the playback-control list.
584 */
585 vcdplayer_read_status_t
586 vcdplayer_read (access_t * p_access, uint8_t *p_buf)
587 {
588
589   /* p_access->handle_events (); */
590   uint8_t wait_time=0;
591
592   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
593   if ( p_vcdplayer->i_lsn > p_vcdplayer->end_lsn ) {
594     vcdplayer_read_status_t read_status;
595  
596     /* We've run off of the end of this entry. Do we continue or stop? */
597     dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
598               "end reached, cur: %u, end: %u\n",
599               p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
600
601   handle_item_continuation:
602     read_status = vcdplayer_pbc_is_on( p_vcdplayer )
603       ? vcdplayer_pbc_nav( p_access, &wait_time )
604       : vcdplayer_non_pbc_nav( p_access, &wait_time );
605
606     if (READ_STILL_FRAME == read_status) {
607       *p_buf = wait_time;
608       return READ_STILL_FRAME;
609     }
610
611     if (READ_BLOCK != read_status) return read_status;
612   }
613
614   /* Read the next block.
615  
616     Important note: we probably speed things up by removing "data"
617     and the memcpy to it by extending vcd_image_source_read_mode2
618     to allow a mode to do what's below in addition to its
619     "raw" and "block" mode. It also would probably improve the modularity
620     a little bit as well.
621   */
622
623   {
624     CdIo *p_img = vcdinfo_get_cd_image(p_vcdplayer->vcd);
625     typedef struct {
626       uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
627       uint8_t data    [M2F2_SECTOR_SIZE];
628       uint8_t spare     [4];
629     } vcdsector_t;
630     vcdsector_t vcd_sector;
631
632     do {
633       if (cdio_read_mode2_sector(p_img, &vcd_sector,
634                                  p_vcdplayer->i_lsn, true)!=0) {
635         dbg_print(INPUT_DBG_LSN, "read error\n");
636         p_vcdplayer->i_lsn++;
637         return READ_ERROR;
638       }
639       p_vcdplayer->i_lsn++;
640
641       if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) {
642         /* We've run off of the end of this entry. Do we continue or stop? */
643         dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
644                    "end reached in reading, cur: %u, end: %u\n",
645                    p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
646         break;
647       }
648  
649       /* Check header ID for a padding sector and simply discard
650          these.  It is alleged that VCD's put these in to keep the
651          bitrate constant.
652       */
653     } while((vcd_sector.subheader[2]&~0x01)==0x60);
654
655     if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn )
656       /* We've run off of the end of this entry. Do we continue or stop? */
657       goto handle_item_continuation;
658  
659     memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE);
660     return READ_BLOCK;
661   }
662 }
663
664 /*!
665   Play item assocated with the "default" selection.
666
667   Return false if there was some problem.
668 */
669 bool
670 vcdplayer_play_default( access_t * p_access )
671 {
672   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
673
674   vcdinfo_itemid_t itemid;
675
676   if (!p_vcdplayer) {
677     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
678            "null p_vcdplayer" );
679     return VLC_EGENERIC;
680   }
681  
682
683   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
684          "current: %d" , p_vcdplayer->play_item.num);
685
686   itemid.type = p_vcdplayer->play_item.type;
687
688   if (vcdplayer_pbc_is_on(p_vcdplayer)) {
689
690 #if defined(LIBVCD_VERSION)
691     lid_t lid=vcdinfo_get_multi_default_lid(p_vcdplayer->vcd, p_vcdplayer->i_lid,
692                         p_vcdplayer->i_lsn);
693
694     if (VCDINFO_INVALID_LID != lid) {
695       itemid.num  = lid;
696       itemid.type = VCDINFO_ITEM_TYPE_LID;
697       dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num);
698     } else {
699       dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcdplayer->i_lid);
700       return VLC_EGENERIC;
701     }
702
703 #else
704     vcdinfo_lid_get_pxd(p_vcdplayer->vcd, &(p_vcdplayer->pxd),
705                         p_vcdplayer->i_lid);
706  
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,
713                                                         p_vcdplayer->i_lid),
714                              &itemid.num, "default");
715       break;
716
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" );
721       return false;
722     }
723 #endif /* LIBVCD_VERSION (< 0.7.21) */
724  
725
726   } else {
727
728     /* PBC is not on. "default" selection beginning of current
729        selection . */
730  
731     itemid.num = p_vcdplayer->play_item.num;
732  
733   }
734
735   /** ??? p_vcdplayer->update_title(); ***/
736   vcdplayer_play( p_access, itemid );
737   return VLC_SUCCESS;
738
739 }
740
741 /*!
742   Play item assocated with the "next" selection.
743
744   Return false if there was some problem.
745 */
746 bool
747 vcdplayer_play_next( access_t * p_access )
748 {
749   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
750
751   vcdinfo_obj_t     *p_vcdinfo;
752   vcdinfo_itemid_t   itemid;
753
754   if (!p_vcdplayer) return false;
755
756   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
757          "current: %d" , p_vcdplayer->play_item.num);
758
759   p_vcdinfo = p_vcdplayer->vcd;
760
761   itemid = p_vcdplayer->play_item;
762
763   if  (vcdplayer_pbc_is_on(p_vcdplayer)) {
764
765     vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
766  
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;
775       break;
776
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;
783       break;
784  
785     case PSD_TYPE_END_LIST:
786     case PSD_TYPE_COMMAND_LIST:
787       LOG_WARN( "There is no PBC 'next' selection here" );
788       return false;
789     }
790   } else {
791
792     /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
793  
794     int max_entry = 0;
795
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:
800  
801       switch (p_vcdplayer->play_item.type) {
802       case VCDINFO_ITEM_TYPE_ENTRY:
803         max_entry = p_vcdplayer->i_entries;
804         break;
805       case VCDINFO_ITEM_TYPE_SEGMENT:
806         max_entry = p_vcdplayer->i_segments;
807         break;
808       case VCDINFO_ITEM_TYPE_TRACK:
809         max_entry = p_vcdplayer->i_tracks;
810         break;
811       default: ; /* Handle exceptional cases below */
812       }
813  
814       if (p_vcdplayer->play_item.num+1 < max_entry) {
815         itemid.num = p_vcdplayer->play_item.num+1;
816       } else {
817         LOG_WARN( "At the end - non-PBC 'next' not possible here" );
818         return false;
819       }
820  
821       break;
822  
823     case VCDINFO_ITEM_TYPE_LID:
824       /* Should have handled above. */
825       LOG_WARN( "Internal inconsistency - should not have gotten here." );
826       return false;
827     default:
828       return false;
829     }
830   }
831
832   /** ??? p_vcdplayer->update_title(); ***/
833   vcdplayer_play( p_access, itemid );
834   return VLC_SUCCESS;
835
836 }
837
838 /*!
839   Play item assocated with the "prev" selection.
840
841   Return false if there was some problem.
842 */
843 bool
844 vcdplayer_play_prev( access_t * p_access )
845 {
846   vcdplayer_t      *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
847   vcdinfo_obj_t    *p_vcdinfo  = p_vcdplayer->vcd;
848   vcdinfo_itemid_t  itemid;
849
850   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
851          "current: %d" , p_vcdplayer->play_item.num);
852
853   itemid = p_vcdplayer->play_item;
854
855   if (vcdplayer_pbc_is_on(p_vcdplayer)) {
856
857     vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
858  
859     switch (p_vcdplayer->pxd.descriptor_type) {
860     case PSD_TYPE_SELECTION_LIST:
861     case PSD_TYPE_EXT_SELECTION_LIST:
862       if (p_vcdplayer->pxd.psd == NULL) return false;
863       vcdplayer_update_entry(p_access,
864                              vcdinf_psd_get_prev_offset(p_vcdplayer->pxd.psd),
865                              &itemid.num, "prev");
866       itemid.type = VCDINFO_ITEM_TYPE_LID;
867       break;
868
869     case PSD_TYPE_PLAY_LIST:
870       if (p_vcdplayer->pxd.pld == NULL) return false;
871       vcdplayer_update_entry(p_access,
872                              vcdinf_pld_get_prev_offset(p_vcdplayer->pxd.pld),
873                              &itemid.num, "prev");
874       itemid.type = VCDINFO_ITEM_TYPE_LID;
875       break;
876  
877     case PSD_TYPE_END_LIST:
878     case PSD_TYPE_COMMAND_LIST:
879       LOG_WARN( "There is no PBC 'prev' selection here" );
880       return false;
881     }
882   } else {
883
884     /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
885  
886     int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
887                     ? 0 : 1;
888  
889     if (p_vcdplayer->play_item.num > min_entry) {
890       itemid.num = p_vcdplayer->play_item.num-1;
891     } else {
892       LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
893       return false;
894     }
895  
896   }
897
898   /** ??? p_vcdplayer->update_title(); ***/
899   vcdplayer_play( p_access, itemid );
900   return VLC_SUCCESS;
901
902 }
903
904 /*!
905   Play item assocated with the "return" selection.
906
907   Return false if there was some problem.
908 */
909 bool
910 vcdplayer_play_return( access_t * p_access )
911 {
912   vcdplayer_t      *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
913   vcdinfo_obj_t    *p_vcdinfo  = p_vcdplayer->vcd;
914   vcdinfo_itemid_t  itemid;
915
916   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
917              "current: %d" , p_vcdplayer->play_item.num);
918
919   itemid = p_vcdplayer->play_item;
920
921   if (vcdplayer_pbc_is_on(p_vcdplayer)) {
922
923     vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
924  
925     switch (p_vcdplayer->pxd.descriptor_type) {
926     case PSD_TYPE_SELECTION_LIST:
927     case PSD_TYPE_EXT_SELECTION_LIST:
928       if (p_vcdplayer->pxd.psd == NULL) return false;
929       vcdplayer_update_entry(p_access,
930                              vcdinf_psd_get_return_offset(p_vcdplayer->pxd.psd),
931                              &itemid.num, "return");
932       itemid.type = VCDINFO_ITEM_TYPE_LID;
933       break;
934
935     case PSD_TYPE_PLAY_LIST:
936       if (p_vcdplayer->pxd.pld == NULL) return false;
937       vcdplayer_update_entry(p_access,
938                              vcdinf_pld_get_return_offset(p_vcdplayer->pxd.pld),
939                              &itemid.num, "return");
940       itemid.type = VCDINFO_ITEM_TYPE_LID;
941       break;
942  
943     case PSD_TYPE_END_LIST:
944     case PSD_TYPE_COMMAND_LIST:
945       LOG_WARN( "There is no PBC 'return' selection here" );
946       return false;
947     }
948   } else {
949
950     /* PBC is not on. "Return" selection is min_entry if possible. */
951  
952     p_vcdplayer->play_item.num =
953       (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type)
954       ? 0 : 1;
955  
956   }
957
958   /** ??? p_vcdplayer->update_title(); ***/
959   vcdplayer_play( p_access, itemid );
960   return VLC_SUCCESS;
961
962 }