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