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