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

access.c

00001 /*****************************************************************************
00002  * vcd.c : VCD input module for vlc using libcdio, libvcd and libvcdinfo.
00003  *         vlc-specific things tend to go here.
00004  *****************************************************************************
00005  * Copyright (C) 2000, 2003, 2004, 2005 the VideoLAN team
00006  * $Id: access.c 11815 2005-07-23 11:25:49Z rocky $
00007  *
00008  * Authors: Rocky Bernstein <[email protected]>
00009  *   Some code is based on the non-libcdio VCD plugin (as there really
00010  *   isn't real developer documentation yet on how to write a
00011  *   navigable plugin.)
00012  *
00013  * This program is free software; you can redistribute it and/or modify
00014  * it under the terms of the GNU General Public License as published by
00015  * the Free Software Foundation; either version 2 of the License, or
00016  * (at your option) any later version.
00017  *
00018  * This program is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00026  *****************************************************************************/
00027 
00028 /*****************************************************************************
00029  * Preamble
00030  *****************************************************************************/
00031 
00032 #include <vlc/vlc.h>
00033 #include <vlc/intf.h>
00034 #include <vlc/input.h>
00035 #include "vlc_keys.h"
00036 
00037 #include <cdio/cdio.h>
00038 #include <cdio/cd_types.h>
00039 #include <cdio/logging.h>
00040 #include <cdio/util.h>
00041 #include <libvcd/info.h>
00042 #include <libvcd/logging.h>
00043 #include "vcd.h"
00044 #include "info.h"
00045 #include "intf.h"
00046 
00047 #define FREE_AND_NULL(ptr) free(ptr); ptr = NULL;
00048 
00049 extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
00050                           const vcdinfo_itemid_t *p_itemid );
00051 
00052 /*****************************************************************************
00053  * Local prototypes
00054  *****************************************************************************/
00055 
00056 /* First those which are accessed from outside (via pointers). */
00057 static block_t *VCDReadBlock    ( access_t * );
00058 
00059 static int      VCDControl      ( access_t *p_access, int i_query,
00060                                   va_list args );
00061 
00062 /* Now those which are strictly internal */
00063 static vlc_bool_t  VCDEntryPoints  ( access_t * );
00064 static vlc_bool_t  VCDLIDs         ( access_t * );
00065 static vlc_bool_t  VCDSegments     ( access_t * );
00066 static int  VCDTitles       ( access_t * );
00067 static char *VCDParse       ( access_t *,
00068                               /*out*/ vcdinfo_itemid_t * p_itemid ,
00069                               /*out*/ vlc_bool_t *play_single_item );
00070 
00071 static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
00072                           const char *p_varname, char *p_label,
00073                           const char *p_debug_label );
00074 
00075 static vcdinfo_obj_t *vcd_Open   ( vlc_object_t *p_this, const char *psz_dev );
00076 
00077 /****************************************************************************
00078  * Private functions
00079  ****************************************************************************/
00080 
00081 /* FIXME: This variable is a hack. Would be nice to eliminate the
00082    global-ness. */
00083 
00084 static access_t *p_vcd_access = NULL;
00085 
00086 /* process messages that originate from libcdio. */
00087 static void
00088 cdio_log_handler (cdio_log_level_t level, const char message[])
00089 {
00090   const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
00091   switch (level) {
00092   case CDIO_LOG_DEBUG:
00093   case CDIO_LOG_INFO:
00094     if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
00095       msg_Dbg( p_vcd_access, message);
00096     break;
00097   case CDIO_LOG_WARN:
00098     msg_Warn( p_vcd_access, message);
00099     break;
00100   case CDIO_LOG_ERROR:
00101   case CDIO_LOG_ASSERT:
00102     msg_Err( p_vcd_access, message);
00103     break;
00104   default:
00105     msg_Warn( p_vcd_access, message,
00106             _("The above message had unknown log level"),
00107             level);
00108   }
00109   return;
00110 }
00111 
00112 /* process messages that originate from vcdinfo. */
00113 static void
00114 vcd_log_handler (vcd_log_level_t level, const char message[])
00115 {
00116   vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
00117   switch (level) {
00118   case VCD_LOG_DEBUG:
00119   case VCD_LOG_INFO:
00120     if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
00121       msg_Dbg( p_vcd_access, message);
00122     break;
00123   case VCD_LOG_WARN:
00124     msg_Warn( p_vcd_access, message);
00125     break;
00126   case VCD_LOG_ERROR:
00127   case VCD_LOG_ASSERT:
00128     msg_Err( p_vcd_access, message);
00129     break;
00130   default:
00131     msg_Warn( p_vcd_access, "%s\n%s %d", message,
00132             _("The above message had unknown vcdimager log level"),
00133             level);
00134   }
00135   return;
00136 }
00137 
00138 /*****************************************************************************
00139   VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
00140   NULL is returned if something went wrong.
00141  *****************************************************************************/
00142 static block_t *
00143 VCDReadBlock( access_t * p_access )
00144 {
00145     vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00146     const int    i_blocks   = p_vcdplayer->i_blocks_per_read;
00147     block_t     *p_block;
00148     int          i_read;
00149     uint8_t     *p_buf;
00150 
00151     i_read = 0;
00152 
00153     dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
00154                (long unsigned int) p_vcdplayer->i_lsn );
00155 
00156     /* Allocate a block for the reading */
00157     if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
00158     {
00159         msg_Err( p_access, "cannot get a new block of size: %i",
00160                  i_blocks * M2F2_SECTOR_SIZE );
00161         block_Release( p_block );
00162         return NULL;
00163     }
00164 
00165     p_buf = (uint8_t *) p_block->p_buffer;
00166     for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
00167     {
00168       vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
00169 
00170       p_access->info.i_pos += M2F2_SECTOR_SIZE;
00171 
00172       switch ( read_status ) {
00173       case READ_END:
00174         /* End reached. Return NULL to indicated this. */
00175         /* We also set the postion to the end so the higher level
00176            (demux?) doesn't try to keep reading. If everything works out
00177            right this shouldn't have to happen.
00178          */
00179 #if 0
00180         if ( p_access->info.i_pos != p_access->info.i_size ) {
00181           msg_Warn( p_access,
00182                     "At end but pos (%llu) is not size (%llu). Adjusting.",
00183                     p_access->info.i_pos, p_access->info.i_size );
00184           p_access->info.i_pos = p_access->info.i_size;
00185         }
00186 #endif
00187 
00188         block_Release( p_block );
00189         return NULL;
00190 
00191       case READ_ERROR:
00192         /* Some sort of error. Should we increment lsn? to skip block?
00193         */
00194         block_Release( p_block );
00195         return NULL;
00196       case READ_STILL_FRAME:
00197         {
00198           /* FIXME The below should be done in an event thread.
00199              Until then...
00200            */
00201 #if 1
00202           msleep( MILLISECONDS_PER_SEC * *p_buf );
00203           VCDSetOrigin(p_access, p_vcdplayer->origin_lsn, p_vcdplayer->i_track,
00204                        &(p_vcdplayer->play_item));
00205           // p_vcd->in_still = VLC_FALSE;
00206           dbg_print(INPUT_DBG_STILL, "still wait time done");
00207 #else
00208           vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);
00209 #endif
00210 
00211           block_Release( p_block );
00212           return NULL;
00213         }
00214 
00215       default:
00216       case READ_BLOCK:
00217         /* Read buffer */
00218         ;
00219       }
00220 
00221       p_buf += M2F2_SECTOR_SIZE;
00222       /* Update seekpoint */
00223       if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
00224       {
00225         unsigned int i_entry = p_vcdplayer->play_item.num+1;
00226         lsn_t        i_lsn   = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
00227         if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
00228         {
00229             const track_t i_track = p_vcdplayer->i_track;
00230 
00231             dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), 
00232                        "entry change to %d, current LSN %u >= end %u",
00233                        i_entry, p_vcdplayer->i_lsn, i_lsn);
00234 
00235             p_vcdplayer->play_item.num = i_entry;
00236 
00237             VCDSetOrigin( p_access,  i_lsn, i_track,
00238                           &(p_vcdplayer->play_item) );
00239         }
00240       }
00241     }
00242 
00243     return p_block;
00244 }
00245 
00246 
00247 /****************************************************************************
00248  * VCDSeek
00249  ****************************************************************************/
00250 int
00251 VCDSeek( access_t * p_access, int64_t i_pos )
00252 {
00253     if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
00254 
00255     {
00256       vcdplayer_t         *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
00257       const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
00258       unsigned int         i_entry = VCDINFO_INVALID_ENTRY;
00259       int i_seekpoint;
00260 
00261       /* Next sector to read */
00262       p_access->info.i_pos = i_pos;
00263       p_vcdplayer->i_lsn = (i_pos / (int64_t) M2F2_SECTOR_SIZE) +
00264         p_vcdplayer->origin_lsn;
00265 
00266       switch (p_vcdplayer->play_item.type) {
00267       case VCDINFO_ITEM_TYPE_TRACK:
00268       case VCDINFO_ITEM_TYPE_ENTRY:
00269         break ;
00270       default:
00271         p_vcdplayer->b_valid_ep = VLC_FALSE;
00272       }
00273 
00274       /* Find entry */
00275       if( p_vcdplayer->b_valid_ep )
00276       {
00277           for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
00278           {
00279               if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
00280               {
00281                   VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
00282                                 "chapter", _("Entry"), "Setting entry" );
00283                   break;
00284               }
00285           }
00286 
00287           {
00288               vcdinfo_itemid_t itemid;
00289               itemid.num  = i_entry;
00290               itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
00291               VCDSetOrigin(p_access, p_vcdplayer->i_lsn, p_vcdplayer->i_track,
00292                            &itemid);
00293           }
00294         }
00295 
00296       dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
00297                  "orig %lu, cur: %lu, offset: %lld, entry %d",
00298                  (long unsigned int) p_vcdplayer->origin_lsn, 
00299                  (long unsigned int) p_vcdplayer->i_lsn, i_pos,
00300                  i_entry );
00301  
00302       /* Find seekpoint */
00303       for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
00304         {
00305           if( i_seekpoint + 1 >= t->i_seekpoint ) break;
00306           if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
00307         }
00308       
00309       /* Update current seekpoint */
00310       if( i_seekpoint != p_access->info.i_seekpoint )
00311         {
00312           dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu", 
00313                      (long unsigned int) i_seekpoint );
00314           p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
00315           p_access->info.i_seekpoint = i_seekpoint;
00316         }
00317 
00318     }
00319     return VLC_SUCCESS;
00320     
00321 }
00322 
00323 /*****************************************************************************
00324   VCDEntryPoints: Reads the information about the entry points on the disc
00325   and initializes area information with that.
00326   Before calling this track information should have been read in.
00327  *****************************************************************************/
00328 static vlc_bool_t
00329 VCDEntryPoints( access_t * p_access )
00330 {
00331   if (!p_access || !p_access->p_sys) return VLC_FALSE;
00332   
00333   {
00334     vcdplayer_t       *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
00335     const unsigned int i_entries   = 
00336       vcdinfo_get_num_entries(p_vcdplayer->vcd);
00337     const track_t      i_last_track 
00338       = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
00339       + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
00340     unsigned int i;
00341    
00342     if (0 == i_entries) {
00343       LOG_ERR ("no entires found -- something is wrong" );
00344       return VLC_FALSE;
00345     }
00346     
00347     p_vcdplayer->p_entries  = malloc( sizeof( lsn_t ) * i_entries );
00348     
00349     if( p_vcdplayer->p_entries == NULL )
00350       {
00351         LOG_ERR ("not enough memory for entry points treatment" );
00352         return VLC_FALSE;
00353       }
00354     
00355     p_vcdplayer->i_entries = i_entries;
00356     
00357     for( i = 0 ; i < i_entries ; i++ )
00358     {
00359         const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
00360         if( i_track <= i_last_track ) {
00361           seekpoint_t *s = vlc_seekpoint_New();
00362           char psz_entry[100];
00363           
00364           snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
00365 
00366           p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
00367           
00368           s->psz_name      = strdup(psz_entry);
00369           s->i_byte_offset = 
00370             (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track))
00371             * M2F2_SECTOR_SIZE;
00372           
00373           dbg_print( INPUT_DBG_MRL, 
00374                      "%s, lsn %d,  byte_offset %ld",
00375                      s->psz_name, p_vcdplayer->p_entries[i], 
00376                      (unsigned long int) s->i_byte_offset);
00377           TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
00378                       p_vcdplayer->p_title[i_track-1]->seekpoint, s );
00379 
00380         } else
00381           msg_Warn( p_access, "wrong track number found in entry points" );
00382     }
00383     p_vcdplayer->b_valid_ep = VLC_TRUE;
00384     return VLC_TRUE;
00385   }
00386 }
00387 
00388 /*****************************************************************************
00389  * VCDSegments: Reads the information about the segments the disc.
00390  *****************************************************************************/
00391 static vlc_bool_t
00392 VCDSegments( access_t * p_access )
00393 {
00394     vcdplayer_t   *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
00395     unsigned int  i;
00396     input_title_t *t;
00397 
00398     p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
00399 
00400     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
00401                "Segments: %d", p_vcdplayer->i_segments);
00402 
00403     if ( 0 == p_vcdplayer->i_segments ) return VLC_FALSE;
00404 
00405     t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
00406     p_vcdplayer->i_titles++;
00407 
00408     t->i_size    = 0; /* Not sure Segments have a size associated */
00409     t->psz_name  = strdup(_("Segments"));
00410 
00411     /* We have one additional segment allocated so we can get the size
00412        by subtracting seg[i+1] - seg[i].
00413      */
00414     p_vcdplayer->p_segments =
00415       malloc( sizeof( lsn_t ) * (p_vcdplayer->i_segments+1) );
00416     if( p_vcdplayer->p_segments == NULL )
00417     {
00418         LOG_ERR ("not enough memory for segment treatment" );
00419         return VLC_FALSE;
00420     }
00421 
00422     for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
00423     {
00424         char psz_segment[100];
00425         seekpoint_t *s = vlc_seekpoint_New();
00426         p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
00427 
00428         snprintf( psz_segment, sizeof(psz_segment), "%s%02d", _("Segment "),
00429                   i );
00430 
00431         s->i_byte_offset = 0; /* Not sure what this would mean here */
00432         s->psz_name  = strdup(psz_segment);
00433         TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
00434     }
00435 
00436     p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
00437       p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
00438       vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
00439                                    p_vcdplayer->i_segments-1);
00440 
00441     return VLC_TRUE;
00442 }
00443 
00444 /*****************************************************************************
00445  Build title table which will be returned via ACCESS_GET_TITLE_INFO.
00446 
00447  We start area addressing for tracks at 1 since the default area 0
00448  is reserved for segments. 
00449  *****************************************************************************/
00450 static int
00451 VCDTitles( access_t * p_access )
00452 {
00453     /* We'll assume a VCD has its first MPEG track
00454        cdio_get_first_track_num()+1 could be used if one wanted to be
00455        very careful about this. Note: cdio_get_first_track() will give the
00456        ISO-9660 track before the MPEG tracks.
00457      */
00458   
00459     if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
00460 
00461     {
00462         vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
00463         track_t      i;
00464 
00465         p_vcdplayer->i_titles = 0;
00466         for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
00467         {
00468             input_title_t *t = p_vcdplayer->p_title[i-1] =
00469               vlc_input_title_New();
00470             char psz_track[80];
00471 
00472             snprintf( psz_track, sizeof(psz_track), "%s%02d", _("Track "),
00473                                                     i );
00474             t->i_size    = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd, 
00475                                                              i ) 
00476               * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
00477             t->psz_name  = strdup(psz_track);
00478 
00479             dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld", i, t->i_size );
00480 
00481             p_vcdplayer->i_titles++;
00482         }
00483 
00484       return VLC_SUCCESS;
00485     }
00486 }
00487 
00488 /*****************************************************************************
00489   VCDLIDs: Reads the LIST IDs from the LOT.
00490  *****************************************************************************/
00491 static vlc_bool_t
00492 VCDLIDs( access_t * p_access )
00493 {
00494     vcdplayer_t   *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
00495     input_title_t *t;
00496     unsigned int   i_lid, i_title;
00497 
00498     p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
00499     p_vcdplayer->i_lid  = VCDINFO_INVALID_ENTRY;
00500 
00501     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
00502                "LIDs: %d", p_vcdplayer->i_lids);
00503 
00504     if ( 0 == p_vcdplayer->i_lids ) return VLC_FALSE;
00505 
00506     if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
00507 
00508       vcdinfo_visit_lot (p_vcdplayer->vcd, false);
00509 
00510 #if FIXED
00511     /*
00512        We need to change libvcdinfo to be more robust when there are
00513        problems reading the extended PSD. Given that area-highlighting and
00514        selection features in the extended PSD haven't been implemented,
00515        it's best then to not try to read this at all.
00516      */
00517       if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
00518         vcdinfo_visit_lot (p_vcdplayer->vcd, VLC_TRUE);
00519 #endif
00520     }
00521 
00522     /* Set up LIDs Navigation Menu */
00523     t = vlc_input_title_New();
00524     t->b_menu = VLC_TRUE;
00525     t->psz_name = strdup( "LIDs" );
00526 
00527     i_title = p_vcdplayer->i_tracks;
00528     for( i_lid =  1 ; i_lid <=  p_vcdplayer->i_lids ; i_lid++ )
00529     {
00530         char psz_lid[100];
00531         seekpoint_t *s = vlc_seekpoint_New();
00532 
00533         snprintf( psz_lid, sizeof(psz_lid), "%s%02d", _("LID "),
00534                   i_lid );
00535 
00536         s->i_byte_offset = 0; /*  A lid doesn't have an offset
00537                                   size associated with it */
00538         s->psz_name  = strdup(psz_lid);
00539         TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
00540     }
00541 
00542 #if DYNAMICALLY_ALLOCATED
00543     TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
00544 #else
00545     p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
00546     p_vcdplayer->i_titles++;
00547 #endif
00548 
00549     return VLC_TRUE;
00550 }
00551 
00552 /*****************************************************************************
00553  * VCDParse: parse command line
00554  *****************************************************************************/
00555 static char *
00556 VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
00557           /*out*/ vlc_bool_t *play_single_item )
00558 {
00559     vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
00560     char        *psz_parser;
00561     char        *psz_source;
00562     char        *psz_next;
00563 
00564     if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
00565       p_itemid->type = VCDINFO_ITEM_TYPE_LID;
00566       p_itemid->num = 1;
00567       *play_single_item = VLC_FALSE;
00568     }
00569     else
00570     {
00571       p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
00572       p_itemid->num = 0;
00573     }
00574 
00575 #ifdef WIN32
00576     /* On Win32 we want the VCD access plugin to be explicitly requested,
00577      * we end up with lots of problems otherwise */
00578     if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
00579 #endif
00580 
00581     if( !p_access->psz_path )
00582     {
00583         return NULL;
00584     }
00585 
00586     psz_parser = psz_source = strdup( p_access->psz_path );
00587 
00588     /* Parse input string :
00589      * [device][@[type][title]] */
00590     while( *psz_parser && *psz_parser != '@' )
00591     {
00592         psz_parser++;
00593     }
00594 
00595     if( *psz_parser == '@' )
00596     {
00597       /* Found the divide between the source name and the
00598          type+entry number. */
00599       unsigned int num;
00600 
00601       *psz_parser = '\0';
00602       ++psz_parser;
00603       if( *psz_parser )
00604         {
00605           switch(*psz_parser) {
00606           case 'E':
00607             p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
00608             ++psz_parser;
00609             *play_single_item = VLC_TRUE;
00610             break;
00611           case 'P':
00612             p_itemid->type = VCDINFO_ITEM_TYPE_LID;
00613             ++psz_parser;
00614             *play_single_item = VLC_FALSE;
00615             break;
00616           case 'S':
00617             p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
00618             ++psz_parser;
00619             *play_single_item = VLC_TRUE;
00620             break;
00621           case 'T':
00622             p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
00623             ++psz_parser;
00624             *play_single_item = VLC_TRUE;
00625             break;
00626           default: ;
00627           }
00628         }
00629 
00630       num = strtol( psz_parser, &psz_next, 10 );
00631       if ( *psz_parser != '\0' && *psz_next == '\0')
00632         {
00633           p_itemid->num = num;
00634         }
00635 
00636     } else {
00637       *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
00638     }
00639 
00640 
00641     if( !*psz_source ) {
00642 
00643       /* No source specified, so figure it out. */
00644       if( !p_access->psz_access ) return NULL;
00645 
00646       psz_source = config_GetPsz( p_access, "vcd" );
00647 
00648       if( !psz_source || 0==strlen(psz_source) ) {
00649         /* Scan for a CD-ROM drive with a VCD in it. */
00650         char **cd_drives = cdio_get_devices_with_cap( NULL,
00651                             ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
00652                               |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
00653                                                      VLC_TRUE );
00654         if( NULL == cd_drives ) return NULL;
00655         if( cd_drives[0] == NULL )
00656         {
00657          cdio_free_device_list( cd_drives );
00658           return NULL;
00659         }
00660         psz_source = strdup( cd_drives[0] );
00661         cdio_free_device_list( cd_drives );
00662       }
00663     }
00664 
00665     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
00666                "source=%s entry=%d type=%d",
00667                psz_source, p_itemid->num, p_itemid->type);
00668 
00669     return psz_source;
00670 }
00671 
00672 /*
00673    Sets start origin for subsequent seeks/reads
00674 */
00675 void
00676 VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
00677               const vcdinfo_itemid_t *p_itemid )
00678 {
00679   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
00680 
00681   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
00682              "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
00683              i_track );
00684 
00685   vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
00686 
00687   switch (p_vcdplayer->play_item.type) {
00688   case VCDINFO_ITEM_TYPE_ENTRY:
00689       VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
00690                     "chapter", _("Entry"), "Setting entry/segment");
00691       p_access->info.i_title     = i_track-1;
00692       if (p_vcdplayer->b_track_length) 
00693       {
00694         p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
00695         p_access->info.i_pos  = (int64_t) M2F2_SECTOR_SIZE *
00696           (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track) - i_lsn) ;
00697       } else {
00698         p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
00699           vcdinfo_get_entry_sect_count(p_vcdplayer->vcd, p_itemid->num);
00700         p_access->info.i_pos = 0;
00701       }
00702       dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %llu, pos: %llu", 
00703                  p_access->info.i_size, p_access->info.i_pos );
00704       p_access->info.i_seekpoint = p_itemid->num;
00705       break;
00706 
00707   case VCDINFO_ITEM_TYPE_SEGMENT:
00708       VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
00709                   "chapter", _("Segment"),  "Setting entry/segment");
00710       /* The last title entry is the for segments (when segments exist
00711          and they must here. The segment seekpoints are stored after
00712          the entry seekpoints and (zeroed) lid seekpoints.
00713       */
00714       p_access->info.i_title     = p_vcdplayer->i_titles - 1;
00715       p_access->info.i_size      = 0; /* No seeking on stills, please. */
00716       p_access->info.i_pos       = 0;
00717       p_access->info.i_seekpoint = p_vcdplayer->i_entries
00718         + p_vcdplayer->i_lids + p_itemid->num;
00719       break;
00720 
00721   case VCDINFO_ITEM_TYPE_TRACK:
00722       p_access->info.i_title     = i_track-1;
00723       p_access->info.i_size      = p_vcdplayer->p_title[i_track-1]->i_size;
00724       p_access->info.i_pos       = 0;
00725       p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
00726                                                            i_track);
00727       break;
00728 
00729   default:
00730       msg_Warn( p_access, "can't set origin for play type %d",
00731                 p_vcdplayer->play_item.type );
00732   }
00733 
00734   p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
00735     |  INPUT_UPDATE_SEEKPOINT;
00736 
00737   VCDUpdateTitle( p_access );
00738 
00739 }
00740 
00741 /*****************************************************************************
00742  * vcd_Open: Opens a VCD device or file initializes, a list of
00743    tracks, segements and entry lsns and sizes and returns an opaque handle.
00744  *****************************************************************************/
00745 static vcdinfo_obj_t *
00746 vcd_Open( vlc_object_t *p_this, const char *psz_dev )
00747 {
00748     access_t    *p_access = (access_t *)p_this;
00749     vcdplayer_t *p_vcdplayer    = (vcdplayer_t *) p_access->p_sys;
00750     vcdinfo_obj_t *p_vcdobj;
00751     char  *actual_dev;
00752     unsigned int i;
00753 
00754     dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
00755 
00756     if( !psz_dev ) return NULL;
00757 
00758     actual_dev=strdup(psz_dev);
00759     if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
00760          VCDINFO_OPEN_VCD) {
00761       free(actual_dev);
00762       return NULL;
00763     }
00764     free(actual_dev);
00765 
00766     /*
00767        Save summary info on tracks, segments and entries...
00768     */
00769 
00770     if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
00771       p_vcdplayer->track = (vcdplayer_play_item_info_t *)
00772         calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
00773 
00774       for (i=0; i<p_vcdplayer->i_tracks; i++) {
00775         unsigned int track_num=i+1;
00776         p_vcdplayer->track[i].size  =
00777           vcdinfo_get_track_sect_count(p_vcdobj, track_num);
00778         p_vcdplayer->track[i].start_LSN =
00779           vcdinfo_get_track_lsn(p_vcdobj, track_num);
00780       }
00781     } else
00782       p_vcdplayer->track = NULL;
00783 
00784     if ( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
00785       p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
00786         calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
00787 
00788       for (i=0; i<p_vcdplayer->i_entries; i++) {
00789         p_vcdplayer->entry[i].size =
00790           vcdinfo_get_entry_sect_count(p_vcdobj, i);
00791         p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lsn(p_vcdobj, i);
00792       }
00793     } else
00794       p_vcdplayer->entry = NULL;
00795 
00796     if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
00797       p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
00798         calloc(p_vcdplayer->i_segments,  sizeof(vcdplayer_play_item_info_t));
00799 
00800       for (i=0; i<p_vcdplayer->i_segments; i++) {
00801         p_vcdplayer->segment[i].size =
00802           vcdinfo_get_seg_sector_count(p_vcdobj, i);
00803         p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
00804       }
00805     } else
00806       p_vcdplayer->segment = NULL;
00807 
00808     return p_vcdobj;
00809 }
00810 
00811 /****************************************************************************
00812  Update the "varname" variable to i_num without triggering a callback.
00813 ****************************************************************************/
00814 static void
00815 VCDUpdateVar( access_t *p_access, int i_num, int i_action,
00816               const char *p_varname, char *p_label,
00817               const char *p_debug_label)
00818 {
00819   vlc_value_t val;
00820   val.i_int = i_num;
00821   if (p_access) {
00822     const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
00823     dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
00824   }
00825   if (p_label) {
00826     vlc_value_t text;
00827     text.psz_string = p_label;
00828     var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
00829   }
00830   var_Change( p_access, p_varname, i_action, &val, NULL );
00831 }
00832 
00833 
00834 /*****************************************************************************
00835  * Public routines.
00836  *****************************************************************************/
00837 
00838 /*****************************************************************************
00839   VCDOpen: open VCD.
00840   read in meta-information about VCD: the number of tracks, segments,
00841   entries, size and starting information. Then set up state variables so
00842   that we read/seek starting at the location specified.
00843 
00844   On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
00845   and VLC_EGENERIC for some other error.
00846  *****************************************************************************/
00847 int
00848 VCDOpen ( vlc_object_t *p_this )
00849 {
00850     access_t         *p_access = (access_t *)p_this;
00851     vcdplayer_t      *p_vcdplayer;
00852     char             *psz_source;
00853     vcdinfo_itemid_t  itemid;
00854     vlc_bool_t        play_single_item = VLC_FALSE;
00855 
00856     p_access->pf_read          = NULL;
00857     p_access->pf_block         = VCDReadBlock; 
00858     p_access->pf_control       = VCDControl;
00859     p_access->pf_seek          = VCDSeek;
00860 
00861     p_access->info.i_update    = 0;
00862     p_access->info.i_size      = 0;
00863     p_access->info.i_pos       = 0;
00864     p_access->info.b_eof       = VLC_FALSE;
00865     p_access->info.i_title     = 0;
00866     p_access->info.i_seekpoint = 0;
00867 
00868     p_vcdplayer = malloc( sizeof(vcdplayer_t) );
00869 
00870     if( p_vcdplayer == NULL )
00871     {
00872         LOG_ERR ("out of memory" );
00873         return VLC_ENOMEM;
00874     }
00875 
00876     p_vcdplayer->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
00877     p_access->p_sys = (access_sys_t *) p_vcdplayer;
00878 
00879     /* Set where to log errors messages from libcdio. */
00880     p_vcd_access = p_access;
00881     cdio_log_set_handler ( cdio_log_handler );
00882     vcd_log_set_handler ( vcd_log_handler );
00883 
00884     psz_source = VCDParse( p_access, &itemid, &play_single_item );
00885 
00886     if ( NULL == psz_source )
00887     {
00888       free( p_vcdplayer );
00889       return( VLC_EGENERIC );
00890     }
00891 
00892     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
00893                psz_source, p_access->psz_path );
00894 
00895     p_vcdplayer->psz_source        = strdup(psz_source);
00896     p_vcdplayer->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
00897                                                     "-blocks-per-read" );
00898     p_vcdplayer->b_track_length    = config_GetInt( p_this, MODULE_STRING
00899                                                     "-track-length" );
00900     p_vcdplayer->in_still          = VLC_FALSE;
00901     p_vcdplayer->play_item.type    = VCDINFO_ITEM_TYPE_NOTFOUND;
00902     p_vcdplayer->p_input           = vlc_object_find( p_access,
00903                                                       VLC_OBJECT_INPUT,
00904                                                       FIND_PARENT );
00905     p_vcdplayer->p_meta            = vlc_meta_New();
00906     p_vcdplayer->p_segments        = NULL;
00907     p_vcdplayer->p_entries         = NULL;
00908 
00909     /* set up input  */
00910 
00911     if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
00912     {
00913         goto err_exit;
00914     }
00915 
00916     p_vcdplayer->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcdplayer->vcd);;
00917 
00918     /* Get track information. */
00919     p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
00920 
00921     if( p_vcdplayer->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcdplayer->i_tracks ) {
00922         vcdinfo_close( p_vcdplayer->vcd );
00923         LOG_ERR ("no movie tracks found" );
00924         goto err_exit;
00925     }
00926 
00927     /* Build Navigation Title table for the tracks. */
00928     VCDTitles( p_access );
00929 
00930     /* Add into the above entry points as "Chapters". */
00931     if( ! VCDEntryPoints( p_access ) )
00932     {
00933         msg_Warn( p_access, "could not read entry points, will not use them" );
00934         p_vcdplayer->b_valid_ep = VLC_FALSE;
00935     }
00936 
00937     /* Initialize LID info and add that as a menu item */
00938     if( ! VCDLIDs( p_access ) )
00939     {
00940         msg_Warn( p_access, "could not read entry LIDs" );
00941     }
00942 
00943     /* Do we set PBC (via LID) on? */
00944     p_vcdplayer->i_lid =
00945       ( VCDINFO_ITEM_TYPE_LID == itemid.type
00946         && p_vcdplayer->i_lids > itemid.num )
00947       ? itemid.num
00948       :  VCDINFO_INVALID_ENTRY;
00949 
00950     /* Initialize segment information and add that a "Track". */
00951     VCDSegments( p_access );
00952 
00953     vcdplayer_play( p_access, itemid );
00954 
00955     p_access->psz_demux = strdup( "ps" );
00956 
00957 #if FIXED
00958     if (play_single_item)
00959       VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
00960                         play_single_item );
00961 #endif
00962 
00963 #if FIXED
00964     p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
00965     p_vcdplayer->p_intf->b_block = VLC_FALSE;
00966 #endif
00967     p_vcdplayer->p_access = p_access;
00968 
00969 #ifdef FIXED
00970     intf_RunThread( p_vcdplayer->p_intf );
00971 #endif
00972 
00973     free( psz_source );
00974 
00975     return VLC_SUCCESS;
00976  err_exit:
00977     if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
00978     free( psz_source );
00979     free( p_vcdplayer );
00980     return VLC_EGENERIC;
00981 }
00982 
00983 /*****************************************************************************
00984  * VCDClose: closes VCD releasing allocated memory.
00985  *****************************************************************************/
00986 void
00987 VCDClose ( vlc_object_t *p_this )
00988 {
00989     access_t    *p_access = (access_t *)p_this;
00990     vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
00991 
00992     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
00993 
00994     {
00995       unsigned int i;
00996       for (i=0 ; i<p_vcdplayer->i_titles; i++)
00997         if (p_vcdplayer->p_title[i])
00998           free(p_vcdplayer->p_title[i]->psz_name);
00999     }
01000     
01001     vcdinfo_close( p_vcdplayer->vcd );
01002 
01003     if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
01004 
01005     FREE_AND_NULL( p_vcdplayer->p_entries );
01006     FREE_AND_NULL( p_vcdplayer->p_segments );
01007     FREE_AND_NULL( p_vcdplayer->psz_source );
01008     FREE_AND_NULL( p_vcdplayer->track );
01009     FREE_AND_NULL( p_vcdplayer->segment );
01010     FREE_AND_NULL( p_vcdplayer->entry );
01011     FREE_AND_NULL( p_access->psz_demux );
01012     FREE_AND_NULL( p_vcdplayer );
01013     p_vcd_access    = NULL;
01014 }
01015 
01016 /*****************************************************************************
01017  * Control: The front-end or vlc engine calls here to ether get
01018  * information such as meta information or plugin capabilities or to
01019  * issue miscellaneous "set" requests.
01020  *****************************************************************************/
01021 static int VCDControl( access_t *p_access, int i_query, va_list args )
01022 {
01023     vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
01024     int         *pi_int;
01025     int i;
01026 
01027     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
01028                "query %d", i_query );
01029 
01030     switch( i_query )
01031     {
01032         /* Pass back a copy of meta information that was gathered when we
01033            during the Open/Initialize call.
01034          */
01035         case ACCESS_GET_META:
01036         {
01037             vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
01038 
01039             dbg_print( INPUT_DBG_EVENT, "get meta info" );
01040 
01041             if ( p_vcdplayer->p_meta ) {
01042               *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
01043               dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
01044             } else
01045               msg_Warn( p_access, "tried to copy NULL meta info" );
01046 
01047             return VLC_SUCCESS;
01048           }
01049           return VLC_EGENERIC;
01050 
01051         case ACCESS_CAN_SEEK:
01052         case ACCESS_CAN_FASTSEEK:
01053         case ACCESS_CAN_PAUSE:
01054         case ACCESS_CAN_CONTROL_PACE:
01055         {
01056             vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
01057 
01058             dbg_print( INPUT_DBG_EVENT,
01059                        "seek/fastseek/pause/can_control_pace" );
01060             *pb_bool = VLC_TRUE;
01061             return VLC_SUCCESS;
01062             break;
01063           }
01064 
01065         /* */
01066         case ACCESS_GET_MTU:
01067             pi_int = (int*)va_arg( args, int * );
01068             *pi_int = (p_vcdplayer->i_blocks_per_read * M2F2_SECTOR_SIZE);
01069             dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
01070             break;
01071 
01072         case ACCESS_GET_PTS_DELAY:
01073         {
01074             int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
01075             *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
01076               * MILLISECONDS_PER_SEC;
01077             dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
01078             return VLC_SUCCESS;
01079             break;
01080         }
01081 
01082         /* */
01083         case ACCESS_SET_PAUSE_STATE:
01084             dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
01085             return VLC_SUCCESS;
01086             break;
01087 
01088         case ACCESS_GET_TITLE_INFO:
01089         {
01090             unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
01091               + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
01092             input_title_t ***ppp_title
01093               = (input_title_t***)va_arg( args, input_title_t*** );
01094             char *psz_mrl = malloc( psz_mrl_max );
01095             unsigned int i;
01096 
01097             pi_int    = (int*)va_arg( args, int* );
01098 
01099             dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
01100                        p_vcdplayer->i_titles );
01101 
01102             if( psz_mrl == NULL ) {
01103                msg_Warn( p_access, "out of memory" );
01104             } else {
01105                snprintf(psz_mrl, psz_mrl_max, "%s%s",
01106                         VCD_MRL_PREFIX, p_vcdplayer->psz_source);
01107                VCDMetaInfo( p_access, psz_mrl );
01108                free(psz_mrl);
01109             }
01110 
01111             /* Duplicate title info */
01112             if( p_vcdplayer->i_titles == 0 )
01113             {
01114                 *pi_int = 0; ppp_title = NULL;
01115                 return VLC_SUCCESS;
01116             }
01117             *pi_int = p_vcdplayer->i_titles;
01118             *ppp_title = malloc( sizeof( input_title_t **)
01119                                          * p_vcdplayer->i_titles );
01120 
01121             if (!*ppp_title) return VLC_ENOMEM;
01122 
01123             for( i = 0; i < p_vcdplayer->i_titles; i++ )
01124             {
01125                 if ( p_vcdplayer->p_title[i] )
01126                   (*ppp_title)[i] =
01127                     vlc_input_title_Duplicate( p_vcdplayer->p_title[i] );
01128             }
01129           }
01130           break;
01131 
01132         case ACCESS_SET_TITLE:
01133             i = (int)va_arg( args, int );
01134 
01135             dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
01136             if( i != p_access->info.i_title )
01137             {
01138                 vcdinfo_itemid_t itemid;
01139                 track_t          i_track = i+1;
01140                 unsigned int     i_entry =
01141                   vcdinfo_track_get_entry( p_vcdplayer->vcd, i_track);
01142 
01143                 if( i < p_vcdplayer->i_tracks ) 
01144                 {
01145                     /* FIXME! For now we are assuming titles are only
01146                        tracks and that track == title+1 */
01147                     itemid.num = i_track;
01148                     itemid.type = VCDINFO_ITEM_TYPE_TRACK;
01149                 } 
01150                 else 
01151                 {
01152                     /* FIXME! i_tracks+2 are Segments, but we need to 
01153                        be able to figure out which segment of that.
01154                        i_tracks+1 is either Segments (if no LIDs) or 
01155                        LIDs otherwise. Again need a way to get the LID 
01156                        number. */
01157                     msg_Warn( p_access,
01158                     "Trying to set track (%u) beyond end of last track (%u).",
01159                               i+1, p_vcdplayer->i_tracks );
01160                     return VLC_EGENERIC;
01161                 }
01162                 
01163                 VCDSetOrigin(p_access,
01164                      vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry),
01165                              i_track, &itemid );
01166             }
01167             break;
01168 
01169         case ACCESS_SET_SEEKPOINT:
01170         {
01171             input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
01172             unsigned int i = (unsigned int)va_arg( args, unsigned int );
01173 
01174             dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
01175             if( t->i_seekpoint > 0 )
01176             {
01177                 track_t i_track = p_access->info.i_title+1;
01178                 lsn_t lsn;
01179 
01180                 /* FIXME! For now we are assuming titles are only
01181                  tracks and that track == title+1 and we the play
01182                  item is entries (not tracks or lids).
01183                  We need to generalize all of this.
01184                 */
01185 
01186                 if (i < p_vcdplayer->i_entries)
01187                 {
01188                     p_vcdplayer->play_item.num  = i;
01189                     p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
01190                     lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
01191                 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
01192                 {
01193                     p_vcdplayer->play_item.num  = i
01194                       = i - p_vcdplayer->i_entries;
01195                     p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
01196                     lsn = 0;
01197                 } else
01198                 {
01199                     p_vcdplayer->play_item.num  = i
01200                       = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
01201                     p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
01202                     lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
01203                 }
01204 
01205                 VCDSetOrigin( p_access,
01206                               vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i),
01207                               i_track, &(p_vcdplayer->play_item) );
01208             }
01209             return VLC_SUCCESS;
01210         }
01211 
01212         case ACCESS_SET_PRIVATE_ID_STATE:
01213             dbg_print( INPUT_DBG_EVENT, "set private id" );
01214             return VLC_EGENERIC;
01215 
01216         default:
01217           msg_Warn( p_access, "unimplemented query in control" );
01218             return VLC_EGENERIC;
01219 
01220     }
01221     return VLC_SUCCESS;
01222 }

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