Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

vcdplayer.c

00001 /*****************************************************************************
00002  * vcdplayer.c : VCD input module for vlc
00003  *               using libcdio, libvcd and libvcdinfo
00004  *****************************************************************************
00005  * Copyright (C) 2003, 2004 Rocky Bernstein <[email protected]>
00006  * $Id: vcdplayer.c 11815 2005-07-23 11:25:49Z rocky $
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00021  *****************************************************************************/
00022 
00023 /*
00024    This contains more of the vlc-independent parts that might be used
00025    in any VCD input module for a media player. However at present there
00026    are vlc-specific structures. See also vcdplayer.c of the xine plugin.
00027  */
00028 /*****************************************************************************
00029  * Preamble
00030  *****************************************************************************/
00031 
00032 #include <vlc/vlc.h>
00033 #include <vlc/input.h>
00034 #include <vlc/intf.h>
00035 
00036 #include "vcd.h"
00037 #include "vcdplayer.h"
00038 #include "intf.h"
00039 
00040 #include <string.h>
00041 
00042 #include <cdio/cdio.h>
00043 #include <cdio/util.h>
00044 #include <libvcd/info.h>
00045 
00046 extern void VCDSetOrigin ( access_t *p_access, lsn_t i_lsn, track_t i_track,
00047                            const vcdinfo_itemid_t * p_itemid );
00048 
00052 bool 
00053 vcdplayer_pbc_is_on( const vcdplayer_t *p_vcdplayer ) 
00054 {
00055   return VCDINFO_INVALID_ENTRY != p_vcdplayer->i_lid; 
00056 }
00057 
00058 /* Given an itemid, return the size for the object (via information
00059    previously stored when opening the vcd). */
00060 static size_t
00061 vcdplayer_get_item_size(access_t * p_access, vcdinfo_itemid_t itemid) 
00062 {
00063   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00064 
00065   switch (itemid.type) {
00066   case VCDINFO_ITEM_TYPE_ENTRY:
00067     return p_vcdplayer->entry[itemid.num].size;
00068     break;
00069   case VCDINFO_ITEM_TYPE_SEGMENT:
00070     return p_vcdplayer->segment[itemid.num].size;
00071     break;
00072   case VCDINFO_ITEM_TYPE_TRACK:
00073     return p_vcdplayer->track[itemid.num-1].size;
00074     break;
00075   case VCDINFO_ITEM_TYPE_LID:
00076     /* Play list number (LID) */
00077     return 0;
00078     break;
00079   case VCDINFO_ITEM_TYPE_NOTFOUND:
00080   case VCDINFO_ITEM_TYPE_SPAREID2:
00081   default:
00082     LOG_ERR("%s %d", "bad item type", itemid.type);
00083     return 0;
00084   }
00085 }
00086 
00087 static void 
00088 vcdplayer_update_entry( access_t * p_access, uint16_t ofs, 
00089                         uint16_t *entry, const char *label)
00090 {
00091   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00092 
00093   if ( ofs == VCDINFO_INVALID_OFFSET ) {
00094     *entry = VCDINFO_INVALID_ENTRY;
00095   } else {
00096     vcdinfo_offset_t *off = vcdinfo_get_offset_t(p_vcdplayer->vcd, ofs);
00097     if (off != NULL) {
00098       *entry = off->lid;
00099       dbg_print(INPUT_DBG_PBC, "%s: LID %d", label, off->lid);
00100     } else
00101       *entry = VCDINFO_INVALID_ENTRY;
00102   }
00103 }
00104 
00105 /* Handles navigation when NOT in PBC reaching the end of a play item. 
00106 
00107    The navigations rules here may be sort of made up, but the intent 
00108    is to do something that's probably right or helpful.
00109 
00110    return true if the caller should return.
00111 */
00112 vcdplayer_read_status_t 
00113 vcdplayer_non_pbc_nav ( access_t *p_access, uint8_t *wait_time )
00114 {
00115   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00116 
00117   /* Not in playback control. Do we advance automatically or stop? */
00118   switch (p_vcdplayer->play_item.type) {
00119   case VCDINFO_ITEM_TYPE_TRACK:
00120   case VCDINFO_ITEM_TYPE_ENTRY: {
00121     if ( ! vcdplayer_play_next( p_access ) )
00122     {
00123         return READ_END;
00124     }
00125     break;
00126   }
00127   case VCDINFO_ITEM_TYPE_SPAREID2:  
00128     dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN), 
00129                "SPAREID2" );
00130     if (p_vcdplayer->in_still)
00131     {
00132       dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN), 
00133                  "End of still spareid2" );
00134       *wait_time = 255;
00135       return READ_STILL_FRAME ;
00136     }
00137     return READ_END;
00138   case VCDINFO_ITEM_TYPE_NOTFOUND:  
00139     LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen");
00140     return READ_ERROR;
00141   case VCDINFO_ITEM_TYPE_LID:  
00142     LOG_ERR ("LID outside PBC -- not supposed to happen");
00143     return READ_ERROR;
00144   case VCDINFO_ITEM_TYPE_SEGMENT:
00145       /* Hack: Just go back and do still again */
00146     /* FIXME */
00147     if (p_vcdplayer->in_still) 
00148     {
00149       dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN), 
00150                  "End of still Segment" );
00151       *wait_time = 10;
00152       return READ_STILL_FRAME;
00153     }
00154     return READ_END;
00155   }
00156   return READ_BLOCK;
00157 }
00158 
00162 static void
00163 _vcdplayer_set_track(access_t * p_access, track_t i_track) 
00164 {
00165   vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
00166   if (i_track < 1 || i_track > p_vcdplayer->i_tracks) 
00167     return;
00168   else {
00169     const vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
00170     vcdinfo_itemid_t itemid;
00171 
00172     itemid.num             = i_track;
00173     itemid.type            = VCDINFO_ITEM_TYPE_TRACK;
00174     p_vcdplayer->in_still  = 0;
00175 
00176     VCDSetOrigin(p_access, vcdinfo_get_track_lsn(p_vcdinfo, i_track), 
00177                  i_track, &itemid);
00178 
00179     dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
00180   }
00181 }
00182 
00186 static void
00187 _vcdplayer_set_entry(access_t * p_access, unsigned int num) 
00188 {
00189   vcdplayer_t   *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
00190   vcdinfo_obj_t *p_vcdinfo   = p_vcdplayer->vcd;
00191   const unsigned int   i_entries = vcdinfo_get_num_entries(p_vcdinfo);
00192 
00193   if (num >= i_entries) {
00194     LOG_ERR("%s %d", "bad entry number", num);
00195     return;
00196   } else {
00197     vcdinfo_itemid_t itemid;
00198 
00199     itemid.num            = num;
00200     itemid.type           = VCDINFO_ITEM_TYPE_ENTRY;
00201     p_vcdplayer->i_still  = 0;
00202 
00203     VCDSetOrigin(p_access, vcdinfo_get_entry_lsn(p_vcdinfo, num),
00204                 vcdinfo_get_track(p_vcdinfo, num), &itemid);
00205 
00206     dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u", 
00207               p_vcdplayer->i_lsn, p_vcdplayer->track_end_lsn);
00208   }
00209 }
00210 
00214 static void
00215 _vcdplayer_set_segment(access_t * p_access, unsigned int num) 
00216 {
00217   vcdplayer_t   *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
00218   vcdinfo_obj_t *p_vcdinfo   = p_vcdplayer->vcd;
00219   segnum_t       i_segs    = vcdinfo_get_num_segments(p_vcdinfo);
00220 
00221   if (num >= i_segs) {
00222     LOG_ERR("%s %d", "bad segment number", num);
00223     return;
00224   } else {
00225     vcdinfo_itemid_t itemid;
00226 
00227     if (VCDINFO_NULL_LSN==p_vcdplayer->i_lsn) {
00228       LOG_ERR("%s %d", 
00229               "Error in getting current segment number", num);
00230       return;
00231     }
00232     
00233     itemid.num = num;
00234     itemid.type = VCDINFO_ITEM_TYPE_SEGMENT;
00235 
00236     VCDSetOrigin(p_access, vcdinfo_get_seg_lsn(p_vcdinfo, num), 0, &itemid);
00237     
00238     dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
00239   }
00240 }
00241 
00242 /* Play entry. */
00243 /* Play a single item. */
00244 static bool
00245 vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
00246 {
00247   vcdplayer_t   *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
00248   vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
00249 
00250   dbg_print(INPUT_DBG_CALL, "called itemid.num: %d, itemid.type: %d",
00251             itemid.num, itemid.type);
00252 
00253   p_vcdplayer->i_still = 0;
00254 
00255   switch (itemid.type) {
00256   case VCDINFO_ITEM_TYPE_SEGMENT: 
00257     {
00258       vcdinfo_video_segment_type_t segtype 
00259         = vcdinfo_get_video_type(p_vcdinfo, itemid.num);
00260       segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
00261 
00262       dbg_print(INPUT_DBG_PBC, "%s (%d), itemid.num: %d", 
00263                 vcdinfo_video_type2str(p_vcdinfo, itemid.num), 
00264                 (int) segtype, itemid.num);
00265 
00266       if (itemid.num >= i_segs) return false;
00267       _vcdplayer_set_segment(p_access, itemid.num);
00268       
00269       switch (segtype)
00270         {
00271         case VCDINFO_FILES_VIDEO_NTSC_STILL:
00272         case VCDINFO_FILES_VIDEO_NTSC_STILL2:
00273         case VCDINFO_FILES_VIDEO_PAL_STILL:
00274         case VCDINFO_FILES_VIDEO_PAL_STILL2:
00275           p_vcdplayer->i_still = STILL_READING;
00276           break;
00277         default:
00278           p_vcdplayer->i_still = 0;
00279         }
00280       
00281       break;
00282     }
00283     
00284   case VCDINFO_ITEM_TYPE_TRACK:
00285     dbg_print(INPUT_DBG_PBC, "track %d", itemid.num);
00286     if (itemid.num < 1 || itemid.num > p_vcdplayer->i_tracks) return false;
00287     _vcdplayer_set_track(p_access, itemid.num);
00288     break;
00289     
00290   case VCDINFO_ITEM_TYPE_ENTRY: 
00291     {
00292       unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
00293       dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num);
00294       if (itemid.num >= i_entries) return false;
00295       _vcdplayer_set_entry(p_access, itemid.num);
00296       break;
00297     }
00298     
00299   case VCDINFO_ITEM_TYPE_LID:
00300     LOG_ERR("%s", "Should have converted p_vcdplayer above");
00301     return false;
00302     break;
00303 
00304   case VCDINFO_ITEM_TYPE_NOTFOUND:
00305     dbg_print(INPUT_DBG_PBC, "play nothing");
00306     p_vcdplayer->i_lsn = p_vcdplayer->end_lsn;
00307     return false;
00308 
00309   default:
00310     LOG_ERR("item type %d not implemented.", itemid.type);
00311     return false;
00312   }
00313   
00314   p_vcdplayer->play_item = itemid;
00315 
00316   /* Some players like xine, have a fifo queue of audio and video buffers
00317      that need to be flushed when playing a new selection. */
00318   /*  if (p_vcdplayer->flush_buffers)
00319       p_vcdplayer->flush_buffers(); */
00320   return true;
00321 }
00322 
00323 /* 
00324    Set's start origin and size for subsequent seeks.  
00325    input: p_vcdplayer->i_lsn, p_vcdplayer->play_item
00326    changed: p_vcdplayer->origin_lsn, p_vcdplayer->end_lsn
00327 */
00328 
00329 void 
00330 vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track,
00331                      const vcdinfo_itemid_t *p_itemid)
00332 {
00333   vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
00334   const size_t i_size= vcdplayer_get_item_size(p_access, *p_itemid);
00335 
00336   if( VCDINFO_NULL_LSN == i_lsn ) 
00337   {
00338       LOG_ERR("%s %d", "Invalid LSN for track", i_track);
00339       return;
00340   }
00341 
00342   p_vcdplayer->play_item.num  = p_itemid->num;
00343   p_vcdplayer->play_item.type = p_itemid->type;
00344   p_vcdplayer->i_lsn          = i_lsn;
00345   p_vcdplayer->end_lsn        = p_vcdplayer->i_lsn + i_size;
00346   p_vcdplayer->origin_lsn     = p_vcdplayer->i_lsn;
00347   p_vcdplayer->i_track        = i_track;
00348   p_vcdplayer->track_lsn      = vcdinfo_get_track_lsn(p_vcdplayer->vcd, 
00349                                                       i_track);
00350   p_vcdplayer->track_end_lsn  = p_vcdplayer->track_lsn + 
00351     vcdinfo_get_track_sect_count(p_vcdplayer->vcd, i_track);
00352 
00353   dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN), 
00354             "lsn %u, end LSN: %u item.num %d, item.type %d", 
00355             p_vcdplayer->i_lsn, p_vcdplayer->end_lsn,
00356             p_vcdplayer->play_item.num, p_vcdplayer->play_item.type);
00357 }
00358 
00365 static bool
00366 vcdplayer_inc_play_item(access_t *p_access)
00367 {
00368 
00369   vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
00370   int noi;
00371 
00372   dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcdplayer->pdi);
00373 
00374   if ( NULL == p_vcdplayer || NULL == p_vcdplayer->pxd.pld  ) return false;
00375 
00376   noi = vcdinf_pld_get_noi(p_vcdplayer->pxd.pld);
00377   
00378   if ( noi <= 0 ) return false;
00379   
00380   /* Handle delays like autowait or wait here? */
00381 
00382   p_vcdplayer->pdi++;
00383 
00384   if ( p_vcdplayer->pdi < 0 || p_vcdplayer->pdi >= noi ) return false;
00385 
00386   else {
00387     uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcdplayer->pxd.pld, 
00388                                                        p_vcdplayer->pdi);
00389     vcdinfo_itemid_t trans_itemid;
00390 
00391     if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
00392     
00393     vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
00394     dbg_print(INPUT_DBG_PBC, "  play-item[%d]: %s",
00395               p_vcdplayer->pdi, vcdinfo_pin2str (trans_itemid_num));
00396     return vcdplayer_play_single_item(p_access, trans_itemid);
00397   }
00398 }
00399 
00400 void
00401 vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid)
00402 {
00403   vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
00404 
00405   dbg_print(INPUT_DBG_CALL, "called itemid.num: %d itemid.type: %d", 
00406             itemid.num, itemid.type);
00407 
00408   if  (!vcdplayer_pbc_is_on(p_vcdplayer)) {
00409     vcdplayer_play_single_item(p_access, itemid);
00410   } else {
00411     /* PBC on - Itemid.num is LID. */
00412 
00413     vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
00414 
00415     if (p_vcdinfo == NULL) return;
00416 
00417     p_vcdplayer->i_lid = itemid.num;
00418     vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), itemid.num);
00419     
00420     switch (p_vcdplayer->pxd.descriptor_type) {
00421       
00422     case PSD_TYPE_SELECTION_LIST:
00423     case PSD_TYPE_EXT_SELECTION_LIST: {
00424       vcdinfo_itemid_t trans_itemid;
00425       uint16_t trans_itemid_num;
00426 
00427       if (p_vcdplayer->pxd.psd == NULL) return;
00428       trans_itemid_num  = vcdinf_psd_get_itemid(p_vcdplayer->pxd.psd);
00429       vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
00430       p_vcdplayer->i_loop     = 1;
00431       p_vcdplayer->loop_item  = trans_itemid;
00432       vcdplayer_play_single_item(p_access, trans_itemid);
00433       break;
00434     }
00435       
00436     case PSD_TYPE_PLAY_LIST: {
00437       if (p_vcdplayer->pxd.pld == NULL) return;
00438       p_vcdplayer->pdi = -1;
00439       vcdplayer_inc_play_item(p_access);
00440       break;
00441     }
00442       
00443     case PSD_TYPE_END_LIST:
00444     case PSD_TYPE_COMMAND_LIST:
00445       
00446     default:
00447       ;
00448     }
00449   }
00450 }
00451 
00452 /* Handles PBC navigation when reaching the end of a play item. */
00453 vcdplayer_read_status_t
00454 vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time )
00455 {
00456   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00457 
00458   /* We are in playback control. */
00459   vcdinfo_itemid_t itemid;
00460 
00461   /* The end of an entry is really the end of the associated 
00462      sequence (or track). */
00463   
00464   if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) && 
00465        (p_vcdplayer->i_lsn < p_vcdplayer->end_lsn) ) {
00466     /* Set up to just continue to the next entry */
00467     p_vcdplayer->play_item.num++;
00468     dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), 
00469                "continuing into next entry: %u", p_vcdplayer->play_item.num);
00470     vcdplayer_play_single_item( p_access, p_vcdplayer->play_item );
00471     /* p_vcdplayer->update_title(); */
00472     return READ_BLOCK;
00473   }
00474   
00475   switch (p_vcdplayer->pxd.descriptor_type) {
00476   case PSD_TYPE_END_LIST:
00477     return READ_END;
00478     break;
00479   case PSD_TYPE_PLAY_LIST: {
00480     if (vcdplayer_inc_play_item(p_access))
00481       return READ_BLOCK;
00482 
00483     /* Set up for caller process wait time given. */
00484     if (p_vcdplayer->i_still) {
00485       *wait_time = vcdinf_get_wait_time(p_vcdplayer->pxd.pld);
00486       dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL), 
00487                 "playlist wait time: %d", *wait_time);
00488       return READ_STILL_FRAME;
00489     }
00490 
00491     /* Wait time has been processed; continue with next entry. */
00492     vcdplayer_update_entry( p_access, 
00493                             vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld),
00494                             &itemid.num, "next" );
00495     itemid.type = VCDINFO_ITEM_TYPE_LID;
00496     vcdplayer_play( p_access, itemid );
00497     break;
00498   }
00499   case PSD_TYPE_SELECTION_LIST:     /* Selection List (+Ext. for SVCD) */
00500   case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
00501     {
00502       uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcdplayer->pxd.psd);
00503       uint16_t max_loop     = vcdinf_get_loop_count(p_vcdplayer->pxd.psd);
00504       vcdinfo_offset_t *offset_timeout_LID = 
00505         vcdinfo_get_offset_t(p_vcdplayer->vcd, timeout_offs);
00506       
00507       dbg_print(INPUT_DBG_PBC, "looped: %d, max_loop %d", 
00508                 p_vcdplayer->i_loop, max_loop);
00509       
00510       /* Set up for caller process wait time given. */
00511       if (p_vcdplayer->i_still) {
00512         *wait_time = vcdinf_get_timeout_time(p_vcdplayer->pxd.psd);
00513         dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
00514                   "playlist wait_time: %d", *wait_time);
00515         return READ_STILL_FRAME;
00516       } 
00517       
00518       /* Wait time has been processed; continue with next entry. */
00519       /* Handle any looping given. */
00520       if ( max_loop == 0 || p_vcdplayer->i_loop < max_loop ) {
00521         p_vcdplayer->i_loop++;
00522         if (p_vcdplayer->i_loop == 0x7f) p_vcdplayer->i_loop = 0;
00523         vcdplayer_play_single_item(p_access, p_vcdplayer->loop_item);
00524         /* if (p_vcdplayer->i_still) p_vcdplayer->force_redisplay();*/
00525         return READ_BLOCK;
00526       }
00527       
00528       /* Looping finished and wait finished. Move to timeout
00529          entry or next entry, or handle still. */
00530       
00531       if (NULL != offset_timeout_LID) {
00532         /* Handle timeout_LID */
00533         itemid.num  = offset_timeout_LID->lid;
00534         itemid.type = VCDINFO_ITEM_TYPE_LID;
00535         dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
00536         vcdplayer_play( p_access, itemid );
00537         return READ_BLOCK;
00538       } else {
00539         int i_selections = vcdinf_get_num_selections(p_vcdplayer->pxd.psd);
00540         if (i_selections > 0) {
00541           /* Pick a random selection. */
00542           unsigned int bsn=vcdinf_get_bsn(p_vcdplayer->pxd.psd);
00543           int rand_selection=bsn +
00544             (int) ((i_selections+0.0)*rand()/(RAND_MAX+1.0));
00545           lid_t rand_lid=vcdinfo_selection_get_lid (p_vcdplayer->vcd, 
00546                                                     p_vcdplayer->i_lid, 
00547                                                     rand_selection);
00548           itemid.num = rand_lid;
00549           itemid.type = VCDINFO_ITEM_TYPE_LID;
00550           dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d", 
00551                     rand_selection - bsn, rand_lid);
00552           vcdplayer_play( p_access, itemid );
00553           return READ_BLOCK;
00554         } else if (p_vcdplayer->i_still) {
00555           /* Hack: Just go back and do still again */
00556           msleep(1000);
00557           return READ_STILL_FRAME;
00558         }
00559       }
00560       break;
00561     }
00562   case VCDINFO_ITEM_TYPE_NOTFOUND:  
00563     LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
00564     break;
00565   case VCDINFO_ITEM_TYPE_SPAREID2:  
00566     LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
00567     break;
00568   case VCDINFO_ITEM_TYPE_LID:  
00569     LOG_ERR( "LID in PBC -- not supposed to happen" );
00570     break;
00571     
00572   default:
00573     ;
00574   }
00575   /* FIXME: Should handle autowait ...  */
00576 
00577   return READ_ERROR;
00578 }
00579 
00587 vcdplayer_read_status_t
00588 vcdplayer_read (access_t * p_access, uint8_t *p_buf)
00589 {
00590 
00591   /* p_access->handle_events (); */
00592   uint8_t wait_time;
00593 
00594   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00595   if ( p_vcdplayer->i_lsn > p_vcdplayer->end_lsn ) {
00596     vcdplayer_read_status_t read_status;
00597     
00598     /* We've run off of the end of this entry. Do we continue or stop? */
00599     dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), 
00600               "end reached, cur: %u, end: %u\n", p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
00601 
00602   handle_item_continuation:
00603     read_status = vcdplayer_pbc_is_on( p_vcdplayer ) 
00604       ? vcdplayer_pbc_nav( p_access, &wait_time ) 
00605       : vcdplayer_non_pbc_nav( p_access, &wait_time );
00606 
00607     if (READ_STILL_FRAME == read_status) {
00608       *p_buf = wait_time;
00609       return READ_STILL_FRAME;
00610     }
00611 
00612     if (READ_BLOCK != read_status) return read_status;
00613   }
00614 
00615   /* Read the next block. 
00616      
00617     Important note: we probably speed things up by removing "data"
00618     and the memcpy to it by extending vcd_image_source_read_mode2
00619     to allow a mode to do what's below in addition to its 
00620     "raw" and "block" mode. It also would probably improve the modularity
00621     a little bit as well.
00622   */
00623 
00624   {
00625     CdIo *p_img = vcdinfo_get_cd_image(p_vcdplayer->vcd);
00626     typedef struct {
00627       uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
00628       uint8_t data      [M2F2_SECTOR_SIZE];
00629       uint8_t spare     [4];
00630     } vcdsector_t;
00631     vcdsector_t vcd_sector;
00632 
00633     do {
00634       if (cdio_read_mode2_sector(p_img, &vcd_sector, 
00635                                  p_vcdplayer->i_lsn, true)!=0) {
00636         dbg_print(INPUT_DBG_LSN, "read error\n");
00637         p_vcdplayer->i_lsn++;
00638         return READ_ERROR;
00639       }
00640       p_vcdplayer->i_lsn++;
00641 
00642       if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) {
00643         /* We've run off of the end of this entry. Do we continue or stop? */
00644         dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), 
00645                    "end reached in reading, cur: %u, end: %u\n", 
00646                    p_vcdplayer->i_lsn, p_vcdplayer->end_lsn);
00647         break;
00648       }
00649       
00650       /* Check header ID for a padding sector and simply discard
00651          these.  It is alleged that VCD's put these in to keep the
00652          bitrate constant.
00653       */
00654     } while((vcd_sector.subheader[2]&~0x01)==0x60);
00655 
00656     if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) 
00657       /* We've run off of the end of this entry. Do we continue or stop? */
00658       goto handle_item_continuation;
00659       
00660     memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE);
00661     return READ_BLOCK;
00662   }
00663 }
00664 
00670 bool 
00671 vcdplayer_play_default( access_t * p_access )
00672 {
00673   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00674 
00675   vcdinfo_itemid_t itemid;
00676 
00677   if (!p_vcdplayer) {
00678     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), 
00679                "null p_vcdplayer" );
00680     return VLC_EGENERIC;
00681   }
00682   
00683 
00684   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), 
00685              "current: %d" , p_vcdplayer->play_item.num);
00686 
00687   itemid.type = p_vcdplayer->play_item.type;
00688 
00689   if  (vcdplayer_pbc_is_on(p_vcdplayer)) {
00690 
00691 #if defined(LIBVCD_VERSION)
00692     lid_t lid=vcdinfo_get_multi_default_lid(p_vcdplayer->vcd, p_vcdplayer->i_lid,
00693                                             p_vcdplayer->i_lsn);
00694 
00695     if (VCDINFO_INVALID_LID != lid) {
00696       itemid.num  = lid;
00697       itemid.type = VCDINFO_ITEM_TYPE_LID;
00698       dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num);
00699     } else {
00700       dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcdplayer->i_lid);
00701       return VLC_EGENERIC;
00702     }
00703 
00704 #else 
00705     vcdinfo_lid_get_pxd(p_vcdplayer->vcd, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
00706     
00707     switch (p_vcdplayer->pxd.descriptor_type) {
00708     case PSD_TYPE_SELECTION_LIST:
00709     case PSD_TYPE_EXT_SELECTION_LIST:
00710       if (p_vcdplayer->pxd.psd == NULL) return false;
00711       vcdplayer_update_entry( p_access, 
00712                               vcdinfo_get_default_offset(p_vcdplayer->vcd, 
00713                                                          p_vcdplayer->i_lid), 
00714                               &itemid.num, "default");
00715       break;
00716 
00717     case PSD_TYPE_PLAY_LIST: 
00718     case PSD_TYPE_END_LIST:
00719     case PSD_TYPE_COMMAND_LIST:
00720       LOG_WARN( "There is no PBC 'default' selection here" );
00721       return false;
00722     }
00723 #endif /* LIBVCD_VERSION (< 0.7.21) */
00724     
00725 
00726   } else {
00727 
00728     /* PBC is not on. "default" selection beginning of current 
00729        selection . */
00730   
00731     itemid.num = p_vcdplayer->play_item.num;
00732     
00733   }
00734 
00736   vcdplayer_play( p_access, itemid );
00737   return VLC_SUCCESS;
00738 
00739 }
00740 
00746 bool 
00747 vcdplayer_play_next( access_t * p_access )
00748 {
00749   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00750 
00751   vcdinfo_obj_t     *p_vcdinfo;
00752   vcdinfo_itemid_t   itemid;
00753 
00754   if (!p_vcdplayer) return false;
00755 
00756   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), 
00757              "current: %d" , p_vcdplayer->play_item.num);
00758 
00759   p_vcdinfo = p_vcdplayer->vcd;
00760 
00761   itemid = p_vcdplayer->play_item;
00762 
00763   if  (vcdplayer_pbc_is_on(p_vcdplayer)) {
00764 
00765     vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
00766     
00767     switch (p_vcdplayer->pxd.descriptor_type) {
00768     case PSD_TYPE_SELECTION_LIST:
00769     case PSD_TYPE_EXT_SELECTION_LIST:
00770       if (p_vcdplayer->pxd.psd == NULL) return false;
00771       vcdplayer_update_entry( p_access, 
00772                               vcdinf_psd_get_next_offset(p_vcdplayer->pxd.psd), 
00773                               &itemid.num, "next");
00774       itemid.type = VCDINFO_ITEM_TYPE_LID;
00775       break;
00776 
00777     case PSD_TYPE_PLAY_LIST: 
00778       if (p_vcdplayer->pxd.pld == NULL) return false;
00779       vcdplayer_update_entry( p_access, 
00780                               vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld), 
00781                               &itemid.num, "next");
00782       itemid.type = VCDINFO_ITEM_TYPE_LID;
00783       break;
00784       
00785     case PSD_TYPE_END_LIST:
00786     case PSD_TYPE_COMMAND_LIST:
00787       LOG_WARN( "There is no PBC 'next' selection here" );
00788       return false;
00789     }
00790   } else {
00791 
00792     /* PBC is not on. "Next" selection is play_item.num+1 if possible. */
00793   
00794     int max_entry = 0;
00795 
00796     switch (p_vcdplayer->play_item.type) {
00797     case VCDINFO_ITEM_TYPE_ENTRY: 
00798     case VCDINFO_ITEM_TYPE_SEGMENT: 
00799     case VCDINFO_ITEM_TYPE_TRACK: 
00800       
00801       switch (p_vcdplayer->play_item.type) {
00802       case VCDINFO_ITEM_TYPE_ENTRY: 
00803         max_entry = p_vcdplayer->i_entries;
00804         break;
00805       case VCDINFO_ITEM_TYPE_SEGMENT: 
00806         max_entry = p_vcdplayer->i_segments;
00807         break;
00808       case VCDINFO_ITEM_TYPE_TRACK: 
00809         max_entry = p_vcdplayer->i_tracks;
00810         break;
00811       default: ; /* Handle exceptional cases below */
00812       }
00813       
00814       if (p_vcdplayer->play_item.num+1 < max_entry) {
00815         itemid.num = p_vcdplayer->play_item.num+1;
00816       } else {
00817         LOG_WARN( "At the end - non-PBC 'next' not possible here" );
00818         return false;
00819       }
00820       
00821       break;
00822       
00823     case VCDINFO_ITEM_TYPE_LID: 
00824       {
00825         /* Should have handled above. */
00826         LOG_WARN( "Internal inconsistency - should not have gotten here." );
00827         return false;
00828       }
00829     default: 
00830       return false;
00831     }
00832   }
00833 
00835   vcdplayer_play( p_access, itemid );
00836   return VLC_SUCCESS;
00837 
00838 }
00839 
00845 bool 
00846 vcdplayer_play_prev( access_t * p_access )
00847 {
00848   vcdplayer_t      *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00849   vcdinfo_obj_t    *p_vcdinfo  = p_vcdplayer->vcd;
00850   vcdinfo_itemid_t  itemid;
00851 
00852   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), 
00853              "current: %d" , p_vcdplayer->play_item.num);
00854 
00855   itemid = p_vcdplayer->play_item;
00856 
00857   if  (vcdplayer_pbc_is_on(p_vcdplayer)) {
00858 
00859     vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
00860     
00861     switch (p_vcdplayer->pxd.descriptor_type) {
00862     case PSD_TYPE_SELECTION_LIST:
00863     case PSD_TYPE_EXT_SELECTION_LIST:
00864       if (p_vcdplayer->pxd.psd == NULL) return false;
00865       vcdplayer_update_entry( p_access, 
00866                               vcdinf_psd_get_prev_offset(p_vcdplayer->pxd.psd), 
00867                               &itemid.num, "prev");
00868       itemid.type = VCDINFO_ITEM_TYPE_LID;
00869       break;
00870 
00871     case PSD_TYPE_PLAY_LIST: 
00872       if (p_vcdplayer->pxd.pld == NULL) return false;
00873       vcdplayer_update_entry( p_access, 
00874                               vcdinf_pld_get_prev_offset(p_vcdplayer->pxd.pld), 
00875                               &itemid.num, "prev");
00876       itemid.type = VCDINFO_ITEM_TYPE_LID;
00877       break;
00878       
00879     case PSD_TYPE_END_LIST:
00880     case PSD_TYPE_COMMAND_LIST:
00881       LOG_WARN( "There is no PBC 'prev' selection here" );
00882       return false;
00883     }
00884   } else {
00885 
00886     /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */
00887   
00888     int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) 
00889       ? 0 : 1;
00890     
00891     if (p_vcdplayer->play_item.num > min_entry) {
00892       itemid.num = p_vcdplayer->play_item.num-1;
00893     } else {
00894       LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
00895       return false;
00896     }
00897       
00898   }
00899 
00901   vcdplayer_play( p_access, itemid );
00902   return VLC_SUCCESS;
00903 
00904 }
00905 
00911 bool 
00912 vcdplayer_play_return( access_t * p_access )
00913 {
00914   vcdplayer_t      *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00915   vcdinfo_obj_t    *p_vcdinfo  = p_vcdplayer->vcd;
00916   vcdinfo_itemid_t  itemid;
00917 
00918   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), 
00919              "current: %d" , p_vcdplayer->play_item.num);
00920 
00921   itemid = p_vcdplayer->play_item;
00922 
00923   if  (vcdplayer_pbc_is_on(p_vcdplayer)) {
00924 
00925     vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid);
00926     
00927     switch (p_vcdplayer->pxd.descriptor_type) {
00928     case PSD_TYPE_SELECTION_LIST:
00929     case PSD_TYPE_EXT_SELECTION_LIST:
00930       if (p_vcdplayer->pxd.psd == NULL) return false;
00931       vcdplayer_update_entry( p_access, 
00932                               vcdinf_psd_get_return_offset(p_vcdplayer->pxd.psd), 
00933                               &itemid.num, "return");
00934       itemid.type = VCDINFO_ITEM_TYPE_LID;
00935       break;
00936 
00937     case PSD_TYPE_PLAY_LIST: 
00938       if (p_vcdplayer->pxd.pld == NULL) return false;
00939       vcdplayer_update_entry( p_access, 
00940                               vcdinf_pld_get_return_offset(p_vcdplayer->pxd.pld), 
00941                               &itemid.num, "return");
00942       itemid.type = VCDINFO_ITEM_TYPE_LID;
00943       break;
00944       
00945     case PSD_TYPE_END_LIST:
00946     case PSD_TYPE_COMMAND_LIST:
00947       LOG_WARN( "There is no PBC 'return' selection here" );
00948       return false;
00949     }
00950   } else {
00951 
00952     /* PBC is not on. "Return" selection is min_entry if possible. */
00953   
00954     p_vcdplayer->play_item.num = 
00955       (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) 
00956       ? 0 : 1;
00957     
00958   }
00959 
00961   vcdplayer_play( p_access, itemid );
00962   return VLC_SUCCESS;
00963 
00964 }
00965 
00966 /* 
00967  * Local variables:
00968  *  c-file-style: "gnu"
00969  *  tab-width: 8
00970  *  indent-tabs-mode: nil
00971  * End:
00972  */

Generated on Tue Dec 20 10:14:27 2005 for vlc-0.8.4a by  doxygen 1.4.2