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