access.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:40k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * vcd.c : VCD input module for vlc using libcdio, libvcd and libvcdinfo.
  3.  *         vlc-specific things tend to go here.
  4.  *****************************************************************************
  5.  * Copyright (C) 2000, 2003, 2004, 2005 the VideoLAN team
  6.  * $Id: 15d02e8cf34e6aadff59fadf97b14ee4cf0197da $
  7.  *
  8.  * Authors: Rocky Bernstein <rocky@panix.com>
  9.  *   Some code is based on the non-libcdio VCD plugin (as there really
  10.  *   isn't real developer documentation yet on how to write a
  11.  *   navigable plugin.)
  12.  *
  13.  * This program is free software; you can redistribute it and/or modify
  14.  * it under the terms of the GNU General Public License as published by
  15.  * the Free Software Foundation; either version 2 of the License, or
  16.  * (at your option) any later version.
  17.  *
  18.  * This program is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21.  * GNU General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU General Public License
  24.  * along with this program; if not, write to the Free Software
  25.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  26.  *****************************************************************************/
  27. /*****************************************************************************
  28.  * Preamble
  29.  *****************************************************************************/
  30. #ifdef HAVE_CONFIG_H
  31. # include "config.h"
  32. #endif
  33. #include <vlc_common.h>
  34. #include <vlc_interface.h>
  35. #include <vlc_input.h>
  36. #include <vlc_access.h>
  37. #include <vlc_charset.h>
  38. #include "vlc_keys.h"
  39. #include <cdio/cdio.h>
  40. #include <cdio/cd_types.h>
  41. #include <cdio/logging.h>
  42. #include <cdio/util.h>
  43. #include <libvcd/info.h>
  44. #include <libvcd/logging.h>
  45. #include "vcd.h"
  46. #include "info.h"
  47. #include "intf.h"
  48. extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
  49.                           const vcdinfo_itemid_t *p_itemid );
  50. /*****************************************************************************
  51.  * Local prototypes
  52.  *****************************************************************************/
  53. /* First those which are accessed from outside (via pointers). */
  54. static block_t *VCDReadBlock    ( access_t * );
  55. static int      VCDControl      ( access_t *p_access, int i_query,
  56.                                   va_list args );
  57. /* Now those which are strictly internal */
  58. static bool  VCDEntryPoints  ( access_t * );
  59. static bool  VCDLIDs         ( access_t * );
  60. static bool  VCDSegments     ( access_t * );
  61. static int  VCDTitles       ( access_t * );
  62. static char *VCDParse       ( access_t *,
  63.                               /*out*/ vcdinfo_itemid_t * p_itemid ,
  64.                               /*out*/ bool *play_single_item );
  65. static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
  66.                           const char *p_varname, char *p_label,
  67.                           const char *p_debug_label );
  68. static vcdinfo_obj_t *vcd_Open   ( vlc_object_t *p_this, const char *psz_dev );
  69. /****************************************************************************
  70.  * Private functions
  71.  ****************************************************************************/
  72. /* FIXME: This variable is a hack. Would be nice to eliminate the
  73.    global-ness. */
  74. static access_t *p_vcd_access = NULL;
  75. /* process messages that originate from libcdio. */
  76. static void
  77. cdio_log_handler (cdio_log_level_t level, const char message[])
  78. {
  79.   const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
  80.   switch (level) {
  81.   case CDIO_LOG_DEBUG:
  82.   case CDIO_LOG_INFO:
  83.     if (p_vcdplayer->i_debug & INPUT_DBG_CDIO)
  84.       msg_Dbg( p_vcd_access, "%s", message);
  85.     break;
  86.   case CDIO_LOG_WARN:
  87.     msg_Warn( p_vcd_access, "%s", message);
  88.     break;
  89.   case CDIO_LOG_ERROR:
  90.   case CDIO_LOG_ASSERT:
  91.     msg_Err( p_vcd_access, "%s", message);
  92.     break;
  93.   default:
  94.     msg_Warn( p_vcd_access, "%sn%s %d", message,
  95.               "The above message had unknown log level",
  96.               level);
  97.   }
  98.   return;
  99. }
  100. /* process messages that originate from vcdinfo. */
  101. static void
  102. vcd_log_handler (vcd_log_level_t level, const char message[])
  103. {
  104.   vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
  105.   switch (level) {
  106.   case VCD_LOG_DEBUG:
  107.   case VCD_LOG_INFO:
  108.     if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO)
  109.       msg_Dbg( p_vcd_access, "%s", message);
  110.     break;
  111.   case VCD_LOG_WARN:
  112.     msg_Warn( p_vcd_access, "%s", message);
  113.     break;
  114.   case VCD_LOG_ERROR:
  115.   case VCD_LOG_ASSERT:
  116.     msg_Err( p_vcd_access, "%s", message);
  117.     break;
  118.   default:
  119.     msg_Warn( p_vcd_access, "%sn%s %d", message,
  120.               "The above message had unknown vcdimager log level",
  121.               level);
  122.   }
  123.   return;
  124. }
  125. /*****************************************************************************
  126.   VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
  127.   NULL is returned if something went wrong.
  128.  *****************************************************************************/
  129. static block_t *
  130. VCDReadBlock( access_t * p_access )
  131. {
  132.     vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
  133.     const int    i_blocks   = p_vcdplayer->i_blocks_per_read;
  134.     block_t     *p_block;
  135.     int          i_read;
  136.     uint8_t     *p_buf;
  137.     i_read = 0;
  138.     dbg_print( (INPUT_DBG_LSN), "lsn: %lu",
  139.                (long unsigned int) p_vcdplayer->i_lsn );
  140.     /* Allocate a block for the reading */
  141.     if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
  142.     {
  143.         msg_Err( p_access, "cannot get a new block of size: %i",
  144.                  i_blocks * M2F2_SECTOR_SIZE );
  145.         block_Release( p_block );
  146.         return NULL;
  147.     }
  148.     p_buf = (uint8_t *) p_block->p_buffer;
  149.     for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
  150.     {
  151.       vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
  152.       p_access->info.i_pos += M2F2_SECTOR_SIZE;
  153.       switch ( read_status ) {
  154.       case READ_END:
  155.         /* End reached. Return NULL to indicated this. */
  156.         /* We also set the postion to the end so the higher level
  157.            (demux?) doesn't try to keep reading. If everything works out
  158.            right this shouldn't have to happen.
  159.          */
  160. #if 0
  161.         if ( p_access->info.i_pos != p_access->info.i_size ) {
  162.           msg_Warn( p_access,
  163.                     "At end but pos (%llu) is not size (%llu). Adjusting.",
  164.                     p_access->info.i_pos, p_access->info.i_size );
  165.           p_access->info.i_pos = p_access->info.i_size;
  166.         }
  167. #endif
  168.         block_Release( p_block );
  169.         return NULL;
  170.       case READ_ERROR:
  171.         /* Some sort of error. Should we increment lsn? to skip block?
  172.         */
  173.         block_Release( p_block );
  174.         return NULL;
  175.       case READ_STILL_FRAME:
  176.         {
  177.           /* FIXME The below should be done in an event thread.
  178.              Until then...
  179.            */
  180. #if 1
  181.           msleep( MILLISECONDS_PER_SEC * *p_buf );
  182.       VCDSetOrigin(p_access, p_vcdplayer->origin_lsn, p_vcdplayer->i_track,
  183.                &(p_vcdplayer->play_item));
  184.           // p_vcd->in_still = false;
  185.           dbg_print(INPUT_DBG_STILL, "still wait time done");
  186. #else
  187.           vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);
  188. #endif
  189.           block_Release( p_block );
  190.           return NULL;
  191.         }
  192.       default:
  193.       case READ_BLOCK:
  194.         /* Read buffer */
  195.         ;
  196.       }
  197.       p_buf += M2F2_SECTOR_SIZE;
  198.       /* Update seekpoint */
  199.       if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type )
  200.       {
  201.         unsigned int i_entry = p_vcdplayer->play_item.num+1;
  202.         lsn_t        i_lsn   = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry);
  203.         if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN )
  204.         {
  205.             const track_t i_track = p_vcdplayer->i_track;
  206.         dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
  207.                "entry change to %d, current LSN %u >= end %u",
  208.                i_entry, p_vcdplayer->i_lsn, i_lsn);
  209.             p_vcdplayer->play_item.num = i_entry;
  210.             VCDSetOrigin( p_access,  i_lsn, i_track,
  211.                           &(p_vcdplayer->play_item) );
  212.         }
  213.       }
  214.     }
  215.     return p_block;
  216. }
  217. /****************************************************************************
  218.  * VCDSeek
  219.  ****************************************************************************/
  220. int
  221. VCDSeek( access_t * p_access, int64_t i_pos )
  222. {
  223.     if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
  224.     {
  225.       vcdplayer_t         *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
  226.       const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
  227.       unsigned int         i_entry = VCDINFO_INVALID_ENTRY;
  228.       int i_seekpoint;
  229.       /* Next sector to read */
  230.       p_access->info.i_pos = i_pos;
  231.       p_vcdplayer->i_lsn = (i_pos / (int64_t) M2F2_SECTOR_SIZE) +
  232.     p_vcdplayer->origin_lsn;
  233.       switch (p_vcdplayer->play_item.type) {
  234.       case VCDINFO_ITEM_TYPE_TRACK:
  235.       case VCDINFO_ITEM_TYPE_ENTRY:
  236.         break ;
  237.       default:
  238.         p_vcdplayer->b_valid_ep = false;
  239.       }
  240.       /* Find entry */
  241.       if( p_vcdplayer->b_valid_ep )
  242.       {
  243.           for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ )
  244.           {
  245.               if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] )
  246.               {
  247.                   VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
  248.                                 "chapter", _("Entry"), "Setting entry" );
  249.                   break;
  250.               }
  251.           }
  252.           {
  253.               vcdinfo_itemid_t itemid;
  254.               itemid.num  = i_entry;
  255.               itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
  256.               VCDSetOrigin(p_access, p_vcdplayer->i_lsn, p_vcdplayer->i_track,
  257.                            &itemid);
  258.           }
  259.         }
  260.       dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
  261.                  "orig %lu, cur: %lu, offset: %lld, entry %d",
  262.                  (long unsigned int) p_vcdplayer->origin_lsn,
  263.                  (long unsigned int) p_vcdplayer->i_lsn, i_pos,
  264.                  i_entry );
  265.  
  266.       /* Find seekpoint */
  267.       for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
  268.     {
  269.       if( i_seekpoint + 1 >= t->i_seekpoint ) break;
  270.       if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
  271.     }
  272.  
  273.       /* Update current seekpoint */
  274.       if( i_seekpoint != p_access->info.i_seekpoint )
  275.     {
  276.       dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu",
  277.              (long unsigned int) i_seekpoint );
  278.       p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
  279.       p_access->info.i_seekpoint = i_seekpoint;
  280.     }
  281.     }
  282.     p_access->info.b_eof = false;
  283.     return VLC_SUCCESS;
  284.  
  285. }
  286. /*****************************************************************************
  287.   VCDEntryPoints: Reads the information about the entry points on the disc
  288.   and initializes area information with that.
  289.   Before calling this track information should have been read in.
  290.  *****************************************************************************/
  291. static bool
  292. VCDEntryPoints( access_t * p_access )
  293. {
  294.   if (!p_access || !p_access->p_sys) return false;
  295.  
  296.   {
  297.     vcdplayer_t       *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
  298.     const unsigned int i_entries   =
  299.       vcdinfo_get_num_entries(p_vcdplayer->vcd);
  300.     const track_t      i_last_track
  301.       = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd))
  302.       + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd));
  303.     unsigned int i;
  304.  
  305.     if (0 == i_entries) {
  306.       LOG_ERR ("no entires found -- something is wrong" );
  307.       return false;
  308.     }
  309.  
  310.     p_vcdplayer->p_entries  = malloc( sizeof( lsn_t ) * i_entries );
  311.  
  312.     if( p_vcdplayer->p_entries == NULL )
  313.       {
  314.     LOG_ERR ("not enough memory for entry points treatment" );
  315.     return false;
  316.       }
  317.  
  318.     p_vcdplayer->i_entries = i_entries;
  319.  
  320.     for( i = 0 ; i < i_entries ; i++ )
  321.     {
  322.     const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i);
  323.     if( i_track <= i_last_track ) {
  324.       seekpoint_t *s = vlc_seekpoint_New();
  325.       char psz_entry[100];
  326.     
  327.       snprintf(psz_entry, sizeof(psz_entry), "%s %02d", _("Entry"), i );
  328.       p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
  329.     
  330.       s->psz_name      = strdup(psz_entry);
  331.       s->i_byte_offset =
  332.         (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track))
  333.         * M2F2_SECTOR_SIZE;
  334.     
  335.       dbg_print( INPUT_DBG_MRL,
  336.              "%s, lsn %d,  byte_offset %ld",
  337.              s->psz_name, p_vcdplayer->p_entries[i],
  338.              (unsigned long int) s->i_byte_offset);
  339.           TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint,
  340.                       p_vcdplayer->p_title[i_track-1]->seekpoint, s );
  341.         } else
  342.           msg_Warn( p_access, "wrong track number found in entry points" );
  343.     }
  344.     p_vcdplayer->b_valid_ep = true;
  345.     return true;
  346.   }
  347. }
  348. /*****************************************************************************
  349.  * VCDSegments: Reads the information about the segments the disc.
  350.  *****************************************************************************/
  351. static bool
  352. VCDSegments( access_t * p_access )
  353. {
  354.     vcdplayer_t   *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
  355.     unsigned int  i;
  356.     input_title_t *t;
  357.     p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd);
  358.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
  359.                "Segments: %d", p_vcdplayer->i_segments);
  360.     if ( 0 == p_vcdplayer->i_segments ) return false;
  361.     t = p_vcdplayer->p_title[p_vcdplayer->i_titles] = vlc_input_title_New();
  362.     p_vcdplayer->i_titles++;
  363.     t->i_size    = 0; /* Not sure Segments have a size associated */
  364.     t->psz_name  = strdup(_("Segments"));
  365.     /* We have one additional segment allocated so we can get the size
  366.        by subtracting seg[i+1] - seg[i].
  367.      */
  368.     p_vcdplayer->p_segments =
  369.       malloc( sizeof( lsn_t ) * (p_vcdplayer->i_segments+1) );
  370.     if( p_vcdplayer->p_segments == NULL )
  371.     {
  372.         LOG_ERR ("not enough memory for segment treatment" );
  373.         return false;
  374.     }
  375.     for( i = 0 ; i < p_vcdplayer->i_segments ; i++ )
  376.     {
  377.         char psz_segment[100];
  378.         seekpoint_t *s = vlc_seekpoint_New();
  379.         p_vcdplayer->p_segments[i] = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
  380.         snprintf( psz_segment, sizeof(psz_segment), "%s %02d", _("Segment"),
  381.                   i );
  382.         s->i_byte_offset = 0; /* Not sure what this would mean here */
  383.         s->psz_name  = strdup(psz_segment);
  384.         TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
  385.     }
  386.     p_vcdplayer->p_segments[p_vcdplayer->i_segments] =
  387.       p_vcdplayer->p_segments[p_vcdplayer->i_segments-1]+
  388.       vcdinfo_get_seg_sector_count(p_vcdplayer->vcd,
  389.                                    p_vcdplayer->i_segments-1);
  390.     return true;
  391. }
  392. /*****************************************************************************
  393.  Build title table which will be returned via ACCESS_GET_TITLE_INFO.
  394.  We start area addressing for tracks at 1 since the default area 0
  395.  is reserved for segments.
  396.  *****************************************************************************/
  397. static int
  398. VCDTitles( access_t * p_access )
  399. {
  400.     /* We'll assume a VCD has its first MPEG track
  401.        cdio_get_first_track_num()+1 could be used if one wanted to be
  402.        very careful about this. Note: cdio_get_first_track() will give the
  403.        ISO-9660 track before the MPEG tracks.
  404.      */
  405.  
  406.     if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
  407.     {
  408.         vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
  409.         track_t      i;
  410.         p_vcdplayer->i_titles = 0;
  411.         for( i = 1 ; i <= p_vcdplayer->i_tracks ; i++ )
  412.         {
  413.             input_title_t *t = p_vcdplayer->p_title[i-1] =
  414.               vlc_input_title_New();
  415.             char psz_track[80];
  416.             snprintf( psz_track, sizeof(psz_track), "%s %02d", _("Track"),
  417.                                                     i );
  418.             t->i_size    = (int64_t) vcdinfo_get_track_size( p_vcdplayer->vcd,
  419.                                  i )
  420.           * M2F2_SECTOR_SIZE / CDIO_CD_FRAMESIZE ;
  421.             t->psz_name  = strdup(psz_track);
  422.         dbg_print( INPUT_DBG_MRL, "track[%d] i_size: %lld", i, t->i_size );
  423.             p_vcdplayer->i_titles++;
  424.         }
  425.       return VLC_SUCCESS;
  426.     }
  427. }
  428. /*****************************************************************************
  429.   VCDLIDs: Reads the LIST IDs from the LOT.
  430.  *****************************************************************************/
  431. static bool
  432. VCDLIDs( access_t * p_access )
  433. {
  434.     vcdplayer_t   *p_vcdplayer = (vcdplayer_t *) p_access->p_sys;
  435.     input_title_t *t;
  436.     unsigned int   i_lid, i_title;
  437.     p_vcdplayer->i_lids = vcdinfo_get_num_LIDs(p_vcdplayer->vcd);
  438.     p_vcdplayer->i_lid  = VCDINFO_INVALID_ENTRY;
  439.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
  440.                "LIDs: %d", p_vcdplayer->i_lids);
  441.     if ( 0 == p_vcdplayer->i_lids ) return false;
  442.     if (vcdinfo_read_psd (p_vcdplayer->vcd)) {
  443.       vcdinfo_visit_lot (p_vcdplayer->vcd, false);
  444. #ifdef FIXED
  445.     /*
  446.        We need to change libvcdinfo to be more robust when there are
  447.        problems reading the extended PSD. Given that area-highlighting and
  448.        selection features in the extended PSD haven't been implemented,
  449.        it's best then to not try to read this at all.
  450.      */
  451.       if (vcdinfo_get_psd_x_size(p_vcdplayer->vcd))
  452.         vcdinfo_visit_lot (p_vcdplayer->vcd, true);
  453. #endif
  454.     }
  455.     /* Set up LIDs Navigation Menu */
  456.     t = vlc_input_title_New();
  457.     t->b_menu = true;
  458.     t->psz_name = strdup( "LIDs" );
  459.     i_title = p_vcdplayer->i_tracks;
  460.     for( i_lid =  1 ; i_lid <=  p_vcdplayer->i_lids ; i_lid++ )
  461.     {
  462.         char psz_lid[100];
  463.         seekpoint_t *s = vlc_seekpoint_New();
  464.         snprintf( psz_lid, sizeof(psz_lid), "%s %02d", _("LID"),
  465.                   i_lid );
  466.         s->i_byte_offset = 0; /*  A lid doesn't have an offset
  467.                                   size associated with it */
  468.         s->psz_name  = strdup(psz_lid);
  469.         TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
  470.     }
  471. #ifdef DYNAMICALLY_ALLOCATED
  472.     TAB_APPEND( p_vcdplayer->i_titles, p_vcdplayer->p_title, t );
  473. #else
  474.     p_vcdplayer->p_title[p_vcdplayer->i_titles] = t;
  475.     p_vcdplayer->i_titles++;
  476. #endif
  477.     return true;
  478. }
  479. /*****************************************************************************
  480.  * VCDParse: parse command line
  481.  *****************************************************************************/
  482. static char *
  483. VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
  484.           /*out*/ bool *play_single_item )
  485. {
  486.     vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
  487.     char        *psz_parser;
  488.     char        *psz_source;
  489.     char        *psz_next;
  490.     if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
  491.       p_itemid->type = VCDINFO_ITEM_TYPE_LID;
  492.       p_itemid->num = 1;
  493.       *play_single_item = false;
  494.     }
  495.     else
  496.     {
  497.       p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
  498.       p_itemid->num = 0;
  499.     }
  500. #ifdef WIN32
  501.     /* On Win32 we want the VCD access plugin to be explicitly requested,
  502.      * we end up with lots of problems otherwise */
  503.     if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
  504. #endif
  505.     if( !p_access->psz_path )
  506.     {
  507.         return NULL;
  508.     }
  509.     psz_parser = psz_source = strdup( p_access->psz_path );
  510.     /* Parse input string :
  511.      * [device][@[type][title]] */
  512.     while( *psz_parser && *psz_parser != '@' )
  513.     {
  514.         psz_parser++;
  515.     }
  516.     if( *psz_parser == '@' )
  517.     {
  518.       /* Found the divide between the source name and the
  519.          type+entry number. */
  520.       unsigned int num;
  521.       *psz_parser = '';
  522.       ++psz_parser;
  523.       if( *psz_parser )
  524.         {
  525.           switch(*psz_parser) {
  526.           case 'E':
  527.             p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
  528.             ++psz_parser;
  529.             *play_single_item = true;
  530.             break;
  531.           case 'P':
  532.             p_itemid->type = VCDINFO_ITEM_TYPE_LID;
  533.             ++psz_parser;
  534.             *play_single_item = false;
  535.             break;
  536.           case 'S':
  537.             p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
  538.             ++psz_parser;
  539.             *play_single_item = true;
  540.             break;
  541.           case 'T':
  542.             p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
  543.             ++psz_parser;
  544.             *play_single_item = true;
  545.             break;
  546.           default: ;
  547.           }
  548.         }
  549.       num = strtol( psz_parser, &psz_next, 10 );
  550.       if ( *psz_parser != '' && *psz_next == '')
  551.         {
  552.           p_itemid->num = num;
  553.         }
  554.     } else {
  555.       *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
  556.     }
  557.     if( !*psz_source ) {
  558.       /* No source specified, so figure it out. */
  559.       if( !p_access->psz_access ) return NULL;
  560.       psz_source = config_GetPsz( p_access, "vcd" );
  561.       if( !psz_source || 0==strlen(psz_source) ) {
  562.         free( psz_source );
  563.         /* Scan for a CD-ROM drive with a VCD in it. */
  564.         char **cd_drives = cdio_get_devices_with_cap( NULL,
  565.                             ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
  566.                               |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
  567.                                                      true );
  568.         if( NULL == cd_drives ) return NULL;
  569.         if( cd_drives[0] == NULL )
  570.         {
  571.          cdio_free_device_list( cd_drives );
  572.           return NULL;
  573.         }
  574.         psz_source = strdup( cd_drives[0] );
  575.         cdio_free_device_list( cd_drives );
  576.       }
  577.     }
  578.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
  579.                "source=%s entry=%d type=%d",
  580.                psz_source, p_itemid->num, p_itemid->type);
  581.     return psz_source;
  582. }
  583. /*
  584.    Sets start origin for subsequent seeks/reads
  585. */
  586. void
  587. VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track,
  588.               const vcdinfo_itemid_t *p_itemid )
  589. {
  590.   vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys;
  591.   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
  592.              "i_lsn: %lu, track: %d", (long unsigned int) i_lsn,
  593.              i_track );
  594.   vcdplayer_set_origin(p_access, i_lsn, i_track, p_itemid);
  595.   switch (p_vcdplayer->play_item.type) {
  596.   case VCDINFO_ITEM_TYPE_ENTRY:
  597.       VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
  598.                     "chapter", _("Entry"), "Setting entry/segment");
  599.       p_access->info.i_title     = i_track-1;
  600.       if (p_vcdplayer->b_track_length)
  601.       {
  602.     p_access->info.i_size = p_vcdplayer->p_title[i_track-1]->i_size;
  603.     p_access->info.i_pos  = (int64_t) M2F2_SECTOR_SIZE *
  604.       (vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track) - i_lsn) ;
  605.       } else {
  606.     p_access->info.i_size = M2F2_SECTOR_SIZE * (int64_t)
  607.       vcdinfo_get_entry_sect_count(p_vcdplayer->vcd, p_itemid->num);
  608.     p_access->info.i_pos = 0;
  609.       }
  610.       dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "size: %llu, pos: %llu",
  611.          p_access->info.i_size, p_access->info.i_pos );
  612.       p_access->info.i_seekpoint = p_itemid->num;
  613.       break;
  614.   case VCDINFO_ITEM_TYPE_SEGMENT:
  615.       VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
  616.                   "chapter", _("Segment"),  "Setting entry/segment");
  617.       /* The last title entry is the for segments (when segments exist
  618.          and they must here. The segment seekpoints are stored after
  619.          the entry seekpoints and (zeroed) lid seekpoints.
  620.       */
  621.       p_access->info.i_title     = p_vcdplayer->i_titles - 1;
  622.       p_access->info.i_size      = 0; /* No seeking on stills, please. */
  623.       p_access->info.i_pos       = 0;
  624.       p_access->info.i_seekpoint = p_vcdplayer->i_entries
  625.         + p_vcdplayer->i_lids + p_itemid->num;
  626.       break;
  627.   case VCDINFO_ITEM_TYPE_TRACK:
  628.       p_access->info.i_title     = i_track-1;
  629.       p_access->info.i_size      = p_vcdplayer->p_title[i_track-1]->i_size;
  630.       p_access->info.i_pos       = 0;
  631.       p_access->info.i_seekpoint = vcdinfo_track_get_entry(p_vcdplayer->vcd,
  632.                                                            i_track);
  633.       break;
  634.   default:
  635.       msg_Warn( p_access, "can't set origin for play type %d",
  636.                 p_vcdplayer->play_item.type );
  637.   }
  638.   p_access->info.i_update = INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE
  639.     |  INPUT_UPDATE_SEEKPOINT;
  640.   VCDUpdateTitle( p_access );
  641. }
  642. /*****************************************************************************
  643.  * vcd_Open: Opens a VCD device or file initializes, a list of
  644.    tracks, segements and entry lsns and sizes and returns an opaque handle.
  645.  *****************************************************************************/
  646. static vcdinfo_obj_t *
  647. vcd_Open( vlc_object_t *p_this, const char *psz_dev )
  648. {
  649.     access_t    *p_access = (access_t *)p_this;
  650.     vcdplayer_t *p_vcdplayer    = (vcdplayer_t *) p_access->p_sys;
  651.     vcdinfo_obj_t *p_vcdobj;
  652.     char  *actual_dev;
  653.     unsigned int i;
  654.     dbg_print(INPUT_DBG_CALL, "called with %s", psz_dev);
  655.     if( !psz_dev ) return NULL;
  656.     actual_dev= ToLocaleDup(psz_dev);
  657.     if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
  658.          VCDINFO_OPEN_VCD) {
  659.       free(actual_dev);
  660.       return NULL;
  661.     }
  662.     free(actual_dev);
  663.     /*
  664.        Save summary info on tracks, segments and entries...
  665.     */
  666.     if ( 0 < (p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdobj)) ) {
  667.       p_vcdplayer->track = (vcdplayer_play_item_info_t *)
  668.         calloc(p_vcdplayer->i_tracks, sizeof(vcdplayer_play_item_info_t));
  669.       for (i=0; i<p_vcdplayer->i_tracks; i++) {
  670.         unsigned int track_num=i+1;
  671.         p_vcdplayer->track[i].size  =
  672.           vcdinfo_get_track_sect_count(p_vcdobj, track_num);
  673.         p_vcdplayer->track[i].start_LSN =
  674.           vcdinfo_get_track_lsn(p_vcdobj, track_num);
  675.       }
  676.     } else
  677.       p_vcdplayer->track = NULL;
  678.     if ( 0 < (p_vcdplayer->i_entries = vcdinfo_get_num_entries(p_vcdobj)) ) {
  679.       p_vcdplayer->entry = (vcdplayer_play_item_info_t *)
  680.         calloc(p_vcdplayer->i_entries, sizeof(vcdplayer_play_item_info_t));
  681.       for (i=0; i<p_vcdplayer->i_entries; i++) {
  682.         p_vcdplayer->entry[i].size =
  683.           vcdinfo_get_entry_sect_count(p_vcdobj, i);
  684.         p_vcdplayer->entry[i].start_LSN = vcdinfo_get_entry_lsn(p_vcdobj, i);
  685.       }
  686.     } else
  687.       p_vcdplayer->entry = NULL;
  688.     if ( 0 < (p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdobj)) ) {
  689.       p_vcdplayer->segment = (vcdplayer_play_item_info_t *)
  690.         calloc(p_vcdplayer->i_segments,  sizeof(vcdplayer_play_item_info_t));
  691.       for (i=0; i<p_vcdplayer->i_segments; i++) {
  692.         p_vcdplayer->segment[i].size =
  693.           vcdinfo_get_seg_sector_count(p_vcdobj, i);
  694.         p_vcdplayer->segment[i].start_LSN = vcdinfo_get_seg_lsn(p_vcdobj, i);
  695.       }
  696.     } else
  697.       p_vcdplayer->segment = NULL;
  698.     return p_vcdobj;
  699. }
  700. /****************************************************************************
  701.  Update the "varname" variable to i_num without triggering a callback.
  702. ****************************************************************************/
  703. static void
  704. VCDUpdateVar( access_t *p_access, int i_num, int i_action,
  705.               const char *p_varname, char *p_label,
  706.               const char *p_debug_label)
  707. {
  708.   vlc_value_t val;
  709.   val.i_int = i_num;
  710.   if (p_access) {
  711.     const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys;
  712.     dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
  713.   }
  714.   if (p_label) {
  715.     vlc_value_t text;
  716.     text.psz_string = p_label;
  717.     var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
  718.   }
  719.   var_Change( p_access, p_varname, i_action, &val, NULL );
  720. }
  721. /*****************************************************************************
  722.  * Public routines.
  723.  *****************************************************************************/
  724. /*****************************************************************************
  725.   VCDOpen: open VCD.
  726.   read in meta-information about VCD: the number of tracks, segments,
  727.   entries, size and starting information. Then set up state variables so
  728.   that we read/seek starting at the location specified.
  729.   On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
  730.   and VLC_EGENERIC for some other error.
  731.  *****************************************************************************/
  732. int
  733. VCDOpen ( vlc_object_t *p_this )
  734. {
  735.     access_t         *p_access = (access_t *)p_this;
  736.     vcdplayer_t      *p_vcdplayer;
  737.     char             *psz_source;
  738.     vcdinfo_itemid_t  itemid;
  739.     bool        play_single_item = false;
  740.     p_access->pf_read          = NULL;
  741.     p_access->pf_block         = VCDReadBlock;
  742.     p_access->pf_control       = VCDControl;
  743.     p_access->pf_seek          = VCDSeek;
  744.     p_access->info.i_update    = 0;
  745.     p_access->info.i_size      = 0;
  746.     p_access->info.i_pos       = 0;
  747.     p_access->info.b_eof       = false;
  748.     p_access->info.i_title     = 0;
  749.     p_access->info.i_seekpoint = 0;
  750.     p_vcdplayer = malloc( sizeof(vcdplayer_t) );
  751.     if( p_vcdplayer == NULL )
  752.         return VLC_ENOMEM;
  753.     p_vcdplayer->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
  754.     p_access->p_sys = (access_sys_t *) p_vcdplayer;
  755.     /* Set where to log errors messages from libcdio. */
  756.     p_vcd_access = p_access;
  757.     cdio_log_set_handler ( cdio_log_handler );
  758.     vcd_log_set_handler ( vcd_log_handler );
  759.     psz_source = VCDParse( p_access, &itemid, &play_single_item );
  760.     if ( NULL == psz_source )
  761.     {
  762.       free( p_vcdplayer );
  763.       return( VLC_EGENERIC );
  764.     }
  765.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
  766.                psz_source, p_access->psz_path );
  767.     p_vcdplayer->psz_source        = strdup(psz_source);
  768.     p_vcdplayer->i_blocks_per_read = config_GetInt( p_this, MODULE_STRING
  769.                                                     "-blocks-per-read" );
  770.     p_vcdplayer->b_track_length    = config_GetInt( p_this, MODULE_STRING
  771.                                                     "-track-length" );
  772.     p_vcdplayer->in_still          = false;
  773.     p_vcdplayer->play_item.type    = VCDINFO_ITEM_TYPE_NOTFOUND;
  774.     p_vcdplayer->p_input           = vlc_object_find( p_access,
  775.                                                       VLC_OBJECT_INPUT,
  776.                                                       FIND_PARENT );
  777. //    p_vcdplayer->p_meta            = vlc_meta_New();
  778.     p_vcdplayer->p_segments        = NULL;
  779.     p_vcdplayer->p_entries         = NULL;
  780.     /* set up input  */
  781.     if( !(p_vcdplayer->vcd = vcd_Open( p_this, psz_source )) )
  782.     {
  783.         goto err_exit;
  784.     }
  785.     p_vcdplayer->b_svd= (bool) vcdinfo_get_tracksSVD(p_vcdplayer->vcd);;
  786.     /* Get track information. */
  787.     p_vcdplayer->i_tracks = vcdinfo_get_num_tracks(p_vcdplayer->vcd);
  788.     if( p_vcdplayer->i_tracks < 1 || CDIO_INVALID_TRACK == p_vcdplayer->i_tracks ) {
  789.         vcdinfo_close( p_vcdplayer->vcd );
  790.         LOG_ERR ("no movie tracks found" );
  791.         goto err_exit;
  792.     }
  793.     /* Build Navigation Title table for the tracks. */
  794.     VCDTitles( p_access );
  795.     /* Add into the above entry points as "Chapters". */
  796.     if( ! VCDEntryPoints( p_access ) )
  797.     {
  798.         msg_Warn( p_access, "could not read entry points, will not use them" );
  799.         p_vcdplayer->b_valid_ep = false;
  800.     }
  801.     /* Initialize LID info and add that as a menu item */
  802.     if( ! VCDLIDs( p_access ) )
  803.     {
  804.         msg_Warn( p_access, "could not read entry LIDs" );
  805.     }
  806.     /* Do we set PBC (via LID) on? */
  807.     p_vcdplayer->i_lid =
  808.       ( VCDINFO_ITEM_TYPE_LID == itemid.type
  809.         && p_vcdplayer->i_lids > itemid.num )
  810.       ? itemid.num
  811.       :  VCDINFO_INVALID_ENTRY;
  812.     /* Initialize segment information and add that a "Track". */
  813.     VCDSegments( p_access );
  814.     vcdplayer_play( p_access, itemid );
  815.     free( p_access->psz_demux );
  816.     p_access->psz_demux = strdup( "ps" );
  817. #ifdef FIXED
  818.     if (play_single_item)
  819.       VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
  820.                         play_single_item );
  821. #endif
  822. #ifdef FIXED
  823.     p_vcdplayer->p_intf = intf_Create( p_access, "vcdx" );
  824.     p_vcdplayer->p_intf->b_block = false;
  825. #endif
  826.     p_vcdplayer->p_access = p_access;
  827. #ifdef FIXED
  828.     intf_RunThread( p_vcdplayer->p_intf );
  829. #endif
  830.     free( psz_source );
  831.     return VLC_SUCCESS;
  832.  err_exit:
  833.     if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
  834.     free( psz_source );
  835.     free( p_vcdplayer->psz_source );
  836.     free( p_vcdplayer );
  837.     return VLC_EGENERIC;
  838. }
  839. /*****************************************************************************
  840.  * VCDClose: closes VCD releasing allocated memory.
  841.  *****************************************************************************/
  842. void
  843. VCDClose ( vlc_object_t *p_this )
  844. {
  845.     access_t    *p_access = (access_t *)p_this;
  846.     vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
  847.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
  848.     {
  849.       unsigned int i;
  850.       for (i=0 ; i<p_vcdplayer->i_titles; i++)
  851.     if (p_vcdplayer->p_title[i])
  852.       free(p_vcdplayer->p_title[i]->psz_name);
  853.     }
  854.  
  855.     vcdinfo_close( p_vcdplayer->vcd );
  856.     if( p_vcdplayer->p_input ) vlc_object_release( p_vcdplayer->p_input );
  857.     FREENULL( p_vcdplayer->p_entries );
  858.     FREENULL( p_vcdplayer->p_segments );
  859.     FREENULL( p_vcdplayer->psz_source );
  860.     FREENULL( p_vcdplayer->track );
  861.     FREENULL( p_vcdplayer->segment );
  862.     FREENULL( p_vcdplayer->entry );
  863.     FREENULL( p_access->psz_demux );
  864.     FREENULL( p_vcdplayer );
  865.     p_vcd_access    = NULL;
  866. }
  867. /*****************************************************************************
  868.  * Control: The front-end or vlc engine calls here to ether get
  869.  * information such as meta information or plugin capabilities or to
  870.  * issue miscellaneous "set" requests.
  871.  *****************************************************************************/
  872. static int VCDControl( access_t *p_access, int i_query, va_list args )
  873. {
  874.     vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
  875.     int         *pi_int;
  876.     int i;
  877.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
  878.                "query %d", i_query );
  879.     switch( i_query )
  880.     {
  881.         /* Pass back a copy of meta information that was gathered when we
  882.            during the Open/Initialize call.
  883.          */
  884.         case ACCESS_GET_META:
  885.         {
  886.             vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
  887.             dbg_print( INPUT_DBG_EVENT, "get meta info" );
  888. #if 0
  889.             if( p_vcdplayer->p_meta )
  890.             {
  891.                 *pp_meta = vlc_meta_Duplicate( p_vcdplayer->p_meta );
  892.                 dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
  893.             }
  894.             else
  895. #endif
  896.               msg_Warn( p_access, "tried to copy NULL meta info" );
  897.             return VLC_SUCCESS;
  898.           }
  899.           return VLC_EGENERIC;
  900.         case ACCESS_CAN_SEEK:
  901.         case ACCESS_CAN_FASTSEEK:
  902.         case ACCESS_CAN_PAUSE:
  903.         case ACCESS_CAN_CONTROL_PACE:
  904.         {
  905.             bool *pb_bool = (bool*)va_arg( args, bool* );
  906.             dbg_print( INPUT_DBG_EVENT,
  907.                        "seek/fastseek/pause/can_control_pace" );
  908.             *pb_bool = true;
  909.             return VLC_SUCCESS;
  910.             break;
  911.           }
  912.         /* */
  913.         case ACCESS_GET_PTS_DELAY:
  914.         {
  915.             int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
  916.             *pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
  917.               * MILLISECONDS_PER_SEC;
  918.             dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
  919.             return VLC_SUCCESS;
  920.             break;
  921.         }
  922.         /* */
  923.         case ACCESS_SET_PAUSE_STATE:
  924.             dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
  925.             return VLC_SUCCESS;
  926.             break;
  927.         case ACCESS_GET_TITLE_INFO:
  928.         {
  929.             unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX)
  930.               + strlen(p_vcdplayer->psz_source) + sizeof("@E999")+3;
  931.             input_title_t ***ppp_title
  932.               = (input_title_t***)va_arg( args, input_title_t*** );
  933.             char *psz_mrl = malloc( psz_mrl_max );
  934.             unsigned int i;
  935.             pi_int    = (int*)va_arg( args, int* );
  936.             dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
  937.                        p_vcdplayer->i_titles );
  938.             if( psz_mrl  )
  939.             {
  940.                snprintf(psz_mrl, psz_mrl_max, "%s%s",
  941.                         VCD_MRL_PREFIX, p_vcdplayer->psz_source);
  942.                VCDMetaInfo( p_access, psz_mrl );
  943.                free(psz_mrl);
  944.             }
  945.             /* Duplicate title info */
  946.             if( p_vcdplayer->i_titles == 0 )
  947.             {
  948.                 *pi_int = 0; ppp_title = NULL;
  949.                 return VLC_SUCCESS;
  950.             }
  951.             *pi_int = p_vcdplayer->i_titles;
  952.             *ppp_title = malloc( sizeof( input_title_t **)
  953.                                          * p_vcdplayer->i_titles );
  954.             if (!*ppp_title) return VLC_ENOMEM;
  955.             for( i = 0; i < p_vcdplayer->i_titles; i++ )
  956.             {
  957.                 if ( p_vcdplayer->p_title[i] )
  958.                   (*ppp_title)[i] =
  959.                     vlc_input_title_Duplicate( p_vcdplayer->p_title[i] );
  960.             }
  961.           }
  962.           break;
  963.         case ACCESS_SET_TITLE:
  964.             i = (int)va_arg( args, int );
  965.             dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
  966.             if( i != p_access->info.i_title )
  967.             {
  968.                 vcdinfo_itemid_t itemid;
  969.                 track_t          i_track = i+1;
  970.                 unsigned int     i_entry =
  971.                   vcdinfo_track_get_entry( p_vcdplayer->vcd, i_track);
  972.         if( i < p_vcdplayer->i_tracks )
  973.         {
  974.             /* FIXME! For now we are assuming titles are only
  975.                tracks and that track == title+1 */
  976.             itemid.num = i_track;
  977.             itemid.type = VCDINFO_ITEM_TYPE_TRACK;
  978.         }
  979.         else
  980.         {
  981.             /* FIXME! i_tracks+2 are Segments, but we need to
  982.                be able to figure out which segment of that.
  983.                        i_tracks+1 is either Segments (if no LIDs) or
  984.                LIDs otherwise. Again need a way to get the LID
  985.                number. */
  986.             msg_Warn( p_access,
  987.                     "Trying to set track (%u) beyond end of last track (%u).",
  988.                   i+1, p_vcdplayer->i_tracks );
  989.             return VLC_EGENERIC;
  990.         }
  991.         
  992.                 VCDSetOrigin(p_access,
  993.                      vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry),
  994.                              i_track, &itemid );
  995.             }
  996.             break;
  997.         case ACCESS_SET_SEEKPOINT:
  998.         {
  999.             input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title];
  1000.             unsigned int i = (unsigned int)va_arg( args, unsigned int );
  1001.             dbg_print( INPUT_DBG_EVENT, "set seekpoint %d", i );
  1002.             if( t->i_seekpoint > 0 )
  1003.             {
  1004.                 track_t i_track = p_access->info.i_title+1;
  1005.                 lsn_t lsn;
  1006.                 /* FIXME! For now we are assuming titles are only
  1007.                  tracks and that track == title+1 and we the play
  1008.                  item is entries (not tracks or lids).
  1009.                  We need to generalize all of this.
  1010.                 */
  1011.                 if (i < p_vcdplayer->i_entries)
  1012.                 {
  1013.                     p_vcdplayer->play_item.num  = i;
  1014.                     p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
  1015.                     lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i);
  1016.                 } else if ( i < p_vcdplayer->i_entries + p_vcdplayer->i_lids )
  1017.                 {
  1018.                     p_vcdplayer->play_item.num  = i
  1019.                       = i - p_vcdplayer->i_entries;
  1020.                     p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_LID;
  1021.                     lsn = 0;
  1022.                 } else
  1023.                 {
  1024.                     p_vcdplayer->play_item.num  = i
  1025.                       = i - p_vcdplayer->i_entries - p_vcdplayer->i_lids;
  1026.                     p_vcdplayer->play_item.type = VCDINFO_ITEM_TYPE_SEGMENT;
  1027.                     lsn = vcdinfo_get_seg_lsn(p_vcdplayer->vcd, i);
  1028.                 }
  1029.                 VCDSetOrigin( p_access,
  1030.                               vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i),
  1031.                               i_track, &(p_vcdplayer->play_item) );
  1032.             }
  1033.             return VLC_SUCCESS;
  1034.         }
  1035.         case ACCESS_SET_PRIVATE_ID_STATE:
  1036.             dbg_print( INPUT_DBG_EVENT, "set private id" );
  1037.             return VLC_EGENERIC;
  1038.         default:
  1039.           msg_Warn( p_access, "unimplemented query in control" );
  1040.             return VLC_EGENERIC;
  1041.     }
  1042.     return VLC_SUCCESS;
  1043. }