access.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:51k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * vcd.c : VCD input module for vlc
  3.  *         using libcdio, libvcd and libvcdinfo. vlc-specific things tend
  4.  *         to go here.
  5.  *****************************************************************************
  6.  * Copyright (C) 2000, 2003, 2004 VideoLAN
  7.  * $Id: access.c 8313 2004-07-29 15:18:04Z hartman $
  8.  *
  9.  * Authors: Rocky Bernstein <rocky@panix.com>
  10.  *          Johan Bilien <jobi@via.ecp.fr>
  11.  *
  12.  * This program is free software; you can redistribute it and/or modify
  13.  * it under the terms of the GNU General Public License as published by
  14.  * the Free Software Foundation; either version 2 of the License, or
  15.  * (at your option) any later version.
  16.  *
  17.  * This program is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20.  * GNU General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU General Public License
  23.  * along with this program; if not, write to the Free Software
  24.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  25.  *****************************************************************************/
  26. /*****************************************************************************
  27.  * Preamble
  28.  *****************************************************************************/
  29. #include <vlc/vlc.h>
  30. #include <vlc/input.h>
  31. #include <vlc/intf.h>
  32. #include "../../demux/mpeg/system.h"
  33. #include "vcd.h"
  34. #include "vcdplayer.h"
  35. #include "intf.h"
  36. #include <cdio/cdio.h>
  37. #include <cdio/cd_types.h>
  38. #include <cdio/logging.h>
  39. #include <cdio/util.h>
  40. #include <libvcd/info.h>
  41. #include <libvcd/logging.h>
  42. #include "cdrom.h"
  43. /* how many blocks VCDRead will read in each loop */
  44. #define VCD_BLOCKS_ONCE 20
  45. #define VCD_DATA_ONCE   (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE)
  46. #define VCD_MRL_PREFIX "vcdx://"
  47. /*****************************************************************************
  48.  * Local prototypes
  49.  *****************************************************************************/
  50. /* First those which are accessed from outside (via pointers). */
  51. static int  VCDRead         ( input_thread_t *, byte_t *, size_t );
  52. static int  VCDSetProgram   ( input_thread_t *, pgrm_descriptor_t * );
  53. /* Now those which are strictly internal */
  54. static void VCDSetOrigin    ( input_thread_t *, lsn_t origin_lsn,
  55.                               lsn_t cur_lsn, lsn_t end_lsn,
  56.                               int cur_entry, track_t track );
  57. static int  VCDEntryPoints  ( input_thread_t * );
  58. static int  VCDLIDs         ( input_thread_t * );
  59. static int  VCDSegments     ( input_thread_t * );
  60. static void VCDTracks       ( input_thread_t * );
  61. static int  VCDReadSector   ( vlc_object_t *p_this,
  62.                               const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn,
  63.                               byte_t * p_buffer );
  64. static char *VCDParse       ( input_thread_t *,
  65.                               /*out*/ vcdinfo_itemid_t * p_itemid ,
  66.                               /*out*/ vlc_bool_t *play_single_item );
  67. static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action,
  68.                           const char *p_varname, char *p_label,
  69.   const char *p_debug_label );
  70. static vcdinfo_obj_t *vcd_Open   ( vlc_object_t *p_this, const char *psz_dev );
  71. /****************************************************************************
  72.  * Private functions
  73.  ****************************************************************************/
  74. /* FIXME: This variable is a hack. Would be nice to eliminate the
  75.    global-ness. */
  76. static input_thread_t *p_vcd_input = NULL;
  77. /* process messages that originate from libcdio. */
  78. static void
  79. cdio_log_handler (cdio_log_level_t level, const char message[])
  80. {
  81.   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
  82.   switch (level) {
  83.   case CDIO_LOG_DEBUG:
  84.   case CDIO_LOG_INFO:
  85.     if (p_vcd->i_debug & INPUT_DBG_CDIO)
  86.       msg_Dbg( p_vcd_input, message);
  87.     break;
  88.   case CDIO_LOG_WARN:
  89.     msg_Warn( p_vcd_input, message);
  90.     break;
  91.   case CDIO_LOG_ERROR:
  92.   case CDIO_LOG_ASSERT:
  93.     msg_Err( p_vcd_input, message);
  94.     break;
  95.   default:
  96.     msg_Warn( p_vcd_input, message,
  97.             _("The above message had unknown log level"),
  98.             level);
  99.   }
  100.   return;
  101. }
  102. /* process messages that originate from vcdinfo. */
  103. static void
  104. vcd_log_handler (vcd_log_level_t level, const char message[])
  105. {
  106.   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
  107.   switch (level) {
  108.   case VCD_LOG_DEBUG:
  109.   case VCD_LOG_INFO:
  110.     if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
  111.       msg_Dbg( p_vcd_input, message);
  112.     break;
  113.   case VCD_LOG_WARN:
  114.     msg_Warn( p_vcd_input, message);
  115.     break;
  116.   case VCD_LOG_ERROR:
  117.   case VCD_LOG_ASSERT:
  118.     msg_Err( p_vcd_input, message);
  119.     break;
  120.   default:
  121.     msg_Warn( p_vcd_input, "%sn%s %d", message,
  122.             _("The above message had unknown vcdimager log level"),
  123.             level);
  124.   }
  125.   return;
  126. }
  127. /*****************************************************************************
  128.  * VCDRead: reads i_len bytes from the VCD into p_buffer.
  129.  *****************************************************************************
  130.  * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
  131.  * bytes.
  132.  *****************************************************************************/
  133. static int
  134. VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
  135. {
  136.     thread_vcd_data_t *     p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
  137.     int                     i_blocks;
  138.     int                     i_index;
  139.     int                     i_read;
  140.     byte_t                  p_last_sector[ M2F2_SECTOR_SIZE ];
  141.     i_read = 0;
  142.     dbg_print( (INPUT_DBG_CALL), "lsn: %lu", 
  143.        (long unsigned int) p_vcd->cur_lsn );
  144.     /* Compute the number of blocks we have to read */
  145.     i_blocks = i_len / M2F2_SECTOR_SIZE;
  146.     for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
  147.     {
  148.       if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
  149.         vcdplayer_read_status_t read_status;
  150.         /* We've run off of the end of this entry. Do we continue or stop? */
  151.         dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
  152.                    "end reached, cur: %lu", 
  153.    (long unsigned int) p_vcd->cur_lsn );
  154.         read_status = vcdplayer_pbc_is_on( p_vcd )
  155.           ? vcdplayer_pbc_nav( p_input )
  156.           : vcdplayer_non_pbc_nav( p_input );
  157.         switch (read_status) {
  158.         case READ_END:
  159.           /* End reached. Return NULL to indicated this. */
  160.         case READ_ERROR:
  161.           /* Some sort of error. */
  162.           return i_read;
  163.         case READ_STILL_FRAME:
  164.           {
  165.             /* Reached the end of a still frame. */
  166.             byte_t * p_buf = p_buffer;
  167.             pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;;
  168.             p_buf += (i_index*M2F2_SECTOR_SIZE);
  169.             memset(p_buf, 0, M2F2_SECTOR_SIZE);
  170.             p_buf += 2;
  171.             *p_buf = 0x01;
  172.             dbg_print(INPUT_DBG_STILL, "Handled still event");
  173. #if 1
  174.             p_vcd->p_intf->p_sys->b_still = 1;
  175.             var_SetInteger( p_input, "state", PAUSE_S );
  176. #endif
  177.             vlc_mutex_lock( &p_input->stream.stream_lock );
  178.             p_pgrm = p_input->stream.p_selected_program;
  179.             p_pgrm->i_synchro_state = SYNCHRO_REINIT;
  180.             vlc_mutex_unlock( &p_input->stream.stream_lock );
  181.             input_ClockManageControl( p_input, p_pgrm, 0 );
  182.             p_vcd->p_intf->p_sys->b_still = 1;
  183.             var_SetInteger( p_input, "state", PAUSE_S );
  184.             return i_read + M2F2_SECTOR_SIZE;
  185.           }
  186.         default:
  187.         case READ_BLOCK:
  188.           break;
  189.         }
  190.       }
  191.       if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
  192.                           p_vcd->cur_lsn,
  193.                           p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
  194.         {
  195.           LOG_ERR ("could not read sector %lu", 
  196.    (long unsigned int) p_vcd->cur_lsn );
  197.           return -1;
  198.         }
  199.       p_vcd->cur_lsn ++;
  200.       /* Update chapter */
  201.       if( p_vcd->b_valid_ep &&
  202.           /* FIXME kludge so that read does not update chapter
  203.            * when a manual chapter change was requested and not
  204.            * yet accomplished */
  205.           !p_input->stream.p_new_area )
  206.         {
  207.           unsigned int i_entry = p_input->stream.p_selected_area->i_part;
  208.           vlc_mutex_lock( &p_input->stream.stream_lock );
  209.           if( i_entry < p_vcd->num_entries &&
  210.               p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
  211.             {
  212.               dbg_print( INPUT_DBG_PBC,
  213.                          "new entry, i_entry %d, sector %lu, es %u",
  214.                          i_entry, (long unsigned int) p_vcd->cur_lsn,
  215.                          p_vcd->p_entries[i_entry] );
  216.               p_vcd->play_item.num =
  217.                 ++ p_input->stream.p_selected_area->i_part;
  218.               p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
  219.               VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
  220.                             "chapter", _("Entry"), "Setting entry" );
  221.             }
  222.           vlc_mutex_unlock( &p_input->stream.stream_lock );
  223.         }
  224.         i_read += M2F2_SECTOR_SIZE;
  225.     }
  226.     if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
  227.     {
  228.         if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
  229.                             p_vcd->cur_lsn, p_last_sector ) < 0 )
  230.         {
  231.             LOG_ERR ("could not read sector %lu", 
  232.      (long unsigned int) p_vcd->cur_lsn );
  233.             return -1;
  234.         }
  235.         p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
  236.                                    p_last_sector, i_len % M2F2_SECTOR_SIZE );
  237.         i_read += i_len % M2F2_SECTOR_SIZE;
  238.     }
  239.     return i_read;
  240. }
  241. /*****************************************************************************
  242.  * VCDSetProgram: Does nothing since a VCD is mono_program
  243.  *****************************************************************************/
  244. static int
  245. VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
  246. {
  247.     thread_vcd_data_t *     p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
  248.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
  249.     return 0;
  250. }
  251. /*****************************************************************************
  252.  * VCDSetArea: initialize internal data structures and input stream data
  253.    so set subsequent reading and seeking to reflect that we are
  254.    at track x, entry or segment y.
  255.    This is called for each user navigation request, e.g. the GUI
  256.    Chapter/Title selections or in initial MRL parsing.
  257.  ****************************************************************************/
  258. int
  259. VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
  260. {
  261.     thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
  262.     unsigned int i_entry = p_area->i_part;
  263.     track_t i_track      = p_area->i_id;
  264.     int old_seekable     = p_input->stream.b_seekable;
  265.     unsigned int i_nb    = p_area->i_plugin_data + p_area->i_part_nb;
  266.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
  267.                "track: %d, entry %d, seekable %d, area %lx, select area %lx ",
  268.                i_track, i_entry, old_seekable,
  269.                (long unsigned int) p_area,
  270.                (long unsigned int) p_input->stream.p_selected_area );
  271.     /* we can't use the interface slider until initilization is complete */
  272.     p_input->stream.b_seekable = 0;
  273.     if( p_area != p_input->stream.p_selected_area )
  274.     {
  275.         unsigned int i;
  276.         /* If is the result of a track change, make the entry valid. */
  277.         if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
  278.           i_entry = p_area->i_plugin_data;
  279.         /* Change the default area */
  280.         p_input->stream.p_selected_area = p_area;
  281.         /* Update the navigation variables without triggering a callback */
  282.         VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
  283.                       _("Track"), "Setting track");
  284.         var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
  285.         for( i = p_area->i_plugin_data; i < i_nb; i++ )
  286.         {
  287.           VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
  288.                         "chapter",  
  289. p_vcd->play_item.type == VCDINFO_ITEM_TYPE_SEGMENT ?
  290. _("Segment"): _("Entry"),
  291. "Adding entry choice");
  292.         }
  293. if (p_vcd->b_svd) {
  294.   unsigned int audio_type = 
  295.     vcdinfo_get_track_audio_type(p_vcd->vcd, i_track);
  296.   unsigned int i_channels = 
  297.     vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type);
  298.   
  299.   var_Change( p_input, "audio_channels", VLC_VAR_CLEARCHOICES, NULL, 
  300.       NULL );
  301.   
  302.   for( i = 0;  i < i_channels; i++ )
  303.     {
  304.       VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
  305.     "audio_channels",  NULL, "Adding audio choice");
  306.     }
  307. }
  308.     }
  309.     if (i_track == 0)
  310.       VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
  311.                     p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
  312.                     i_entry, 0 );
  313.     else
  314.       VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
  315.                     vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
  316.                     p_vcd->p_sectors[i_track+1],
  317.                     i_entry, i_track );
  318.     p_input->stream.b_seekable = old_seekable;
  319.     /* warn interface that something has changed */
  320.     p_input->stream.b_changed = 1;
  321.     return VLC_SUCCESS;
  322. }
  323. /****************************************************************************
  324.  * VCDSeek
  325.  ****************************************************************************/
  326. void
  327. VCDSeek( input_thread_t * p_input, off_t i_off )
  328. {
  329.     thread_vcd_data_t * p_vcd;
  330.     unsigned int i_entry=0; /* invalid entry */
  331.     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
  332.     p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
  333.     vlc_mutex_lock( &p_input->stream.stream_lock );
  334. #define p_area p_input->stream.p_selected_area
  335.     /* Find entry */
  336.     if( p_vcd->b_valid_ep )
  337.     {
  338.         for( i_entry = 0 ; i_entry < p_vcd->num_entries ; i_entry ++ )
  339.         {
  340.             if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
  341.             {
  342.               VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
  343.                             "chapter", _("Entry"), "Setting entry" );
  344.               break;
  345.             }
  346.         }
  347.         p_vcd->play_item.num  = p_area->i_part = i_entry;
  348.         p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
  349.     }
  350. #undef p_area
  351.     p_input->stream.p_selected_area->i_tell = i_off;
  352.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
  353.                "orig %lu, cur: %lu, offset: %lld, start: %lld, entry %d",
  354.                (long unsigned int) p_vcd->origin_lsn, 
  355.        (long unsigned int) p_vcd->cur_lsn, i_off,
  356.                p_input->stream.p_selected_area->i_start, i_entry );
  357.     vlc_mutex_unlock( &p_input->stream.stream_lock );
  358. }
  359. /*****************************************************************************
  360.   VCDPlay: set up internal structures so seeking/reading places an item.
  361.   itemid: the thing to play.
  362.   user_entry: true if itemid is a user selection (rather than internally-
  363.   generated selection such as via PBC) in which case we may have to adjust
  364.   for differences in numbering.
  365.  *****************************************************************************/
  366. int
  367. VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
  368. {
  369.     thread_vcd_data_t *     p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
  370.     input_area_t *          p_area;
  371.     vlc_bool_t              b_was_still;
  372.     dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %dn",
  373.               itemid.num, itemid.type);
  374.     if (!p_input->p_access_data) return VLC_EGENERIC;
  375.     
  376.     b_was_still = p_vcd->in_still;
  377. #define area p_input->stream.pp_areas
  378.     switch (itemid.type) {
  379.     case VCDINFO_ITEM_TYPE_TRACK:
  380.       /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
  381.        */
  382.       if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
  383.         LOG_ERR ("Invalid track number %d", itemid.num );
  384.         return VLC_EGENERIC;
  385.       }
  386.       p_vcd->in_still  = VLC_FALSE;
  387.       p_area           = area[itemid.num];
  388.       p_area->i_part   = p_area->i_plugin_data;
  389.       p_input->stream.b_seekable = 1;
  390.       break;
  391.     case VCDINFO_ITEM_TYPE_SEGMENT:
  392.       /* Valid segments go from 0...num_segments-1. */
  393.       if (itemid.num >= p_vcd->num_segments) {
  394.         LOG_ERR ( "Invalid segment number: %d", itemid.num );
  395.         return VLC_EGENERIC;
  396.       } else {
  397.         vcdinfo_video_segment_type_t segtype =
  398.           vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
  399.         dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
  400.                   vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
  401.                   (int) segtype, itemid.num);
  402.         p_area           = area[0];
  403.         p_area->i_part   = itemid.num;
  404.         switch (segtype)
  405.           {
  406.           case VCDINFO_FILES_VIDEO_NTSC_STILL:
  407.           case VCDINFO_FILES_VIDEO_NTSC_STILL2:
  408.           case VCDINFO_FILES_VIDEO_PAL_STILL:
  409.           case VCDINFO_FILES_VIDEO_PAL_STILL2:
  410.             p_input->stream.b_seekable = 0;
  411.             p_vcd->in_still = VLC_TRUE;
  412.             break;
  413.           default:
  414.             p_input->stream.b_seekable = 1;
  415.             p_vcd->in_still = VLC_FALSE;
  416.           }
  417.       }
  418.       break;
  419.     case VCDINFO_ITEM_TYPE_LID:
  420.       /* LIDs go from 1..num_lids. */
  421.       if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
  422.         LOG_ERR ( "Invalid LID number: %d", itemid.num );
  423.         return VLC_EGENERIC;
  424.       } else {
  425.         p_vcd->cur_lid = itemid.num;
  426.         vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
  427.         switch (p_vcd->pxd.descriptor_type) {
  428.         case PSD_TYPE_SELECTION_LIST:
  429.         case PSD_TYPE_EXT_SELECTION_LIST: {
  430.           vcdinfo_itemid_t trans_itemid;
  431.           uint16_t trans_itemid_num;
  432.           if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
  433.           trans_itemid_num  = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
  434.           vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
  435.           p_vcd->loop_count = 1;
  436.           p_vcd->loop_item  = trans_itemid;
  437.           return VCDPlay( p_input, trans_itemid );
  438.           break;
  439.         }
  440.         case PSD_TYPE_PLAY_LIST: {
  441.           if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
  442.           p_vcd->pdi = -1;
  443.           return vcdplayer_inc_play_item(p_input)
  444.             ? VLC_SUCCESS : VLC_EGENERIC;
  445.           break;
  446.         }
  447.         case PSD_TYPE_END_LIST:
  448.         case PSD_TYPE_COMMAND_LIST:
  449.         default:
  450.           ;
  451.         }
  452.       }
  453.       return VLC_EGENERIC;
  454.     case VCDINFO_ITEM_TYPE_ENTRY:
  455.       /* Entries go from 0..num_entries-1. */
  456.       if (itemid.num >= p_vcd->num_entries) {
  457.         LOG_ERR ("Invalid entry number: %d", itemid.num );
  458.         return VLC_EGENERIC;
  459.       } else {
  460.         track_t cur_track  = vcdinfo_get_track(p_vcd->vcd,  itemid.num);
  461.         p_vcd->in_still    = VLC_FALSE;
  462.         p_area             = area[cur_track];
  463.         p_area->i_part     = itemid.num;
  464.         p_input->stream.b_seekable = 1;
  465.       }
  466.       break;
  467.     default:
  468.       LOG_ERR ("unknown entry type" );
  469.       return VLC_EGENERIC;
  470.     }
  471.     VCDSetArea( p_input, p_area );
  472. #undef area
  473. #if 1
  474.     if ( p_vcd->in_still != b_was_still ) {
  475.       if (p_input->stream.pp_selected_es) {
  476.         var_SetInteger( p_input, "state", PLAYING_S );
  477.       }
  478.     }
  479. #endif
  480.     p_vcd->play_item = itemid;
  481.     dbg_print( (INPUT_DBG_CALL),
  482.                "i_start %lld, i_size: %lld, i_tell: %lld, lsn %lu",
  483.                p_area->i_start, p_area->i_size,
  484.                p_area->i_tell, 
  485.        (long unsigned int) p_vcd->cur_lsn );
  486.     return VLC_SUCCESS;
  487. }
  488. /*****************************************************************************
  489.   VCDEntryPoints: Reads the information about the entry points on the disc
  490.   and initializes area information with that.
  491.   Before calling this track information should have been read in.
  492.  *****************************************************************************/
  493. static int
  494. VCDEntryPoints( input_thread_t * p_input )
  495. {
  496.     thread_vcd_data_t *               p_vcd;
  497.     unsigned int                      i_nb;
  498.     unsigned int                      i, i_entry_index = 0;
  499.     unsigned int                      i_previous_track = CDIO_INVALID_TRACK;
  500.     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
  501.     i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
  502.     if (0 == i_nb)
  503.       return -1;
  504.     p_vcd->p_entries  = malloc( sizeof( lba_t ) * i_nb );
  505.     if( p_vcd->p_entries == NULL )
  506.     {
  507.         LOG_ERR ("not enough memory for entry points treatment" );
  508.         return -1;
  509.     }
  510.     p_vcd->num_entries = 0;
  511.     for( i = 0 ; i < i_nb ; i++ )
  512.     {
  513.         track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
  514.         if( i_track <= p_input->stream.i_area_nb )
  515.         {
  516.             p_vcd->p_entries[i] =
  517.               vcdinfo_get_entry_lsn(p_vcd->vcd, i);
  518.             p_input->stream.pp_areas[i_track]->i_part_nb ++;
  519.             /* if this entry belongs to a new track */
  520.             if( i_track != i_previous_track )
  521.             {
  522.                 /* i_plugin_data is used to store the first entry of the area*/
  523.                 p_input->stream.pp_areas[i_track]->i_plugin_data =
  524.                                                             i_entry_index;
  525.                 i_previous_track = i_track;
  526.                 p_input->stream.pp_areas[i_track]->i_part_nb = 1;
  527.             }
  528.             i_entry_index ++;
  529.             p_vcd->num_entries ++;
  530.         }
  531.         else
  532.             msg_Warn( p_input, "wrong track number found in entry points" );
  533.     }
  534.     p_vcd->b_valid_ep = VLC_TRUE;
  535.     return 0;
  536. }
  537. /*****************************************************************************
  538.  * VCDSegments: Reads the information about the segments the disc.
  539.  *****************************************************************************/
  540. static int
  541. VCDSegments( input_thread_t * p_input )
  542. {
  543.     thread_vcd_data_t * p_vcd;
  544.     unsigned int        i;
  545.     unsigned int        num_segments;
  546.     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
  547.     num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
  548. #define area p_input->stream.pp_areas
  549.     /* area 0 is reserved for segments. Set Absolute start offset
  550.          and size */
  551.     area[0]->i_plugin_data = 0;
  552.     input_DelArea( p_input, area[0] );
  553.     input_AddArea( p_input, 0, 0 );
  554.     area[0]->i_start = (off_t)p_vcd->p_sectors[0]
  555.       * (off_t)M2F2_SECTOR_SIZE;
  556.     area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
  557.       * (off_t)M2F2_SECTOR_SIZE;
  558.     /* Default Segment  */
  559.     area[0]->i_part = 0;
  560.     /* i_plugin_data is used to store which entry point is the first
  561.        of the track (area) */
  562.     area[0]->i_plugin_data = 0;
  563.     area[0]->i_part_nb = 0;
  564.     dbg_print( INPUT_DBG_MRL,
  565.                "area[0] id: %d, i_start: %lld, i_size: %lld",
  566.                area[0]->i_id, area[0]->i_start, area[0]->i_size );
  567.     if (num_segments == 0) return 0;
  568.     /* We have one additional segment allocated so we can get the size
  569.        by subtracting seg[i+1] - seg[i].
  570.      */
  571.     p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
  572.     if( p_vcd->p_segments == NULL )
  573.     {
  574.         LOG_ERR ("not enough memory for segment treatment" );
  575.         return -1;
  576.     }
  577.     /* Update the navigation variables without triggering a callback */
  578.     VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", _("Track"),
  579.   "Setting track" );
  580.     var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
  581.     for( i = 0 ; i < num_segments ; i++ )
  582.     {
  583.       p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
  584.       area[0]->i_part_nb ++;
  585.       VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
  586.                     "chapter", _("Segment"), "Adding segment choice");
  587.     }
  588. #undef area
  589.     p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
  590.       vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
  591.     return 0;
  592. }
  593. /*****************************************************************************
  594.  VCDTracks: initializes area information.
  595.  Before calling this track information should have been read in.
  596.  *****************************************************************************/
  597. static void
  598. VCDTracks( input_thread_t * p_input )
  599. {
  600.     thread_vcd_data_t * p_vcd;
  601.     unsigned int        i;
  602.     p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
  603. #define area p_input->stream.pp_areas
  604.     /* We start area addressing for tracks at 1 since the default area 0
  605.        is reserved for segments */
  606.     for( i = 1 ; i < p_vcd->num_tracks ; i++ )
  607.     {
  608.         /* Tracks are Program Chains */
  609.         input_AddArea( p_input, i, i );
  610.         /* Absolute start byte offset and byte size */
  611.         area[i]->i_start = (off_t) p_vcd->p_sectors[i]
  612.                            * (off_t)M2F2_SECTOR_SIZE;
  613.         area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
  614.                            * (off_t)M2F2_SECTOR_SIZE;
  615.         /* Current entry being played in track */
  616.         area[i]->i_part = 0;
  617.         /* i_plugin_data is used to store which entry point is the first
  618.          * of the track (area) */
  619.         area[i]->i_plugin_data = 0;
  620.         dbg_print( INPUT_DBG_MRL,
  621.                    "area[%d] id: %d, i_start: %lld, i_size: %lld",
  622.                    i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
  623.     }
  624. #undef area
  625.     return ;
  626. }
  627. /*****************************************************************************
  628.   VCDLIDs: Reads the LIST IDs from the LOT.
  629.  *****************************************************************************/
  630. static int
  631. VCDLIDs( input_thread_t * p_input )
  632. {
  633.     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
  634.     p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
  635.     p_vcd->cur_lid  = VCDINFO_INVALID_ENTRY;
  636.     if (vcdinfo_read_psd (p_vcd->vcd)) {
  637.       vcdinfo_visit_lot (p_vcd->vcd, VLC_FALSE);
  638. #if FIXED
  639.     /*
  640.        We need to change libvcdinfo to be more robust when there are
  641.        problems reading the extended PSD. Given that area-highlighting and
  642.        selection features in the extended PSD haven't been implemented,
  643.        it's best then to not try to read this at all.
  644.      */
  645.       if (vcdinfo_get_psd_x_size(p_vcd->vcd))
  646.         vcdinfo_visit_lot (p_vcd->vcd, VLC_TRUE);
  647. #endif
  648.     }
  649.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
  650.                "num LIDs=%d", p_vcd->num_lids);
  651.     return 0;
  652. }
  653. /*****************************************************************************
  654.  * VCDParse: parse command line
  655.  *****************************************************************************/
  656. static char *
  657. VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid,
  658.           /*out*/ vlc_bool_t *play_single_item )
  659. {
  660.     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
  661.     char *             psz_parser;
  662.     char *             psz_source;
  663.     char *             psz_next;
  664.     if( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
  665.       p_itemid->type = VCDINFO_ITEM_TYPE_LID;
  666.       p_itemid->num = 1;
  667.       *play_single_item = VLC_FALSE;
  668.     }
  669.     else 
  670.     {
  671.       p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
  672.       p_itemid->num = 0;
  673.     }
  674. #ifdef WIN32
  675.     /* On Win32 we want the VCD access plugin to be explicitly requested,
  676.      * we end up with lots of problems otherwise */
  677.     if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
  678. #endif
  679.     if( !p_input->psz_name )
  680.     {
  681.         return NULL;
  682.     }
  683.     psz_parser = psz_source = strdup( p_input->psz_name );
  684.     /* Parse input string :
  685.      * [device][@[type][title]] */
  686.     while( *psz_parser && *psz_parser != '@' )
  687.     {
  688.         psz_parser++;
  689.     }
  690.     if( *psz_parser == '@' )
  691.     {
  692.       /* Found the divide between the source name and the
  693.          type+entry number. */
  694.       unsigned int num;
  695.       *psz_parser = '';
  696.       ++psz_parser;
  697.       if( *psz_parser )
  698.         {
  699.           switch(*psz_parser) {
  700.           case 'E':
  701.             p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
  702.             ++psz_parser;
  703.             *play_single_item = VLC_TRUE;
  704.             break;
  705.           case 'P':
  706.             p_itemid->type = VCDINFO_ITEM_TYPE_LID;
  707.             ++psz_parser;
  708.             *play_single_item = VLC_FALSE;
  709.             break;
  710.           case 'S':
  711.             p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
  712.             ++psz_parser;
  713.             *play_single_item = VLC_TRUE;
  714.             break;
  715.           case 'T':
  716.             p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
  717.             ++psz_parser;
  718.             *play_single_item = VLC_TRUE;
  719.             break;
  720.           default: ;
  721.           }
  722.         }
  723.       num = strtol( psz_parser, &psz_next, 10 );
  724.       if ( *psz_parser != '' && *psz_next == '')
  725.         {
  726.           p_itemid->num = num;
  727.         }
  728.     } else {
  729.       *play_single_item = ( VCDINFO_ITEM_TYPE_LID == p_itemid->type );
  730.     }
  731.     if( !*psz_source ) {
  732.       /* No source specified, so figure it out. */
  733.       if( !p_input->psz_access ) return NULL;
  734.       psz_source = config_GetPsz( p_input, "vcd" );
  735.       if( !psz_source || 0==strlen(psz_source) ) {
  736.         /* Scan for a CD-ROM drive with a VCD in it. */
  737.         char **cd_drives = cdio_get_devices_with_cap( NULL,
  738.                             ( CDIO_FS_ANAL_SVCD | CDIO_FS_ANAL_CVD
  739.                               |CDIO_FS_ANAL_VIDEOCD | CDIO_FS_UNKNOWN ),
  740.                                                      VLC_TRUE );
  741.         if( NULL == cd_drives ) return NULL;
  742.         if( cd_drives[0] == NULL )
  743. {
  744.           cdio_free_device_list( cd_drives );
  745.           return NULL;
  746.         }
  747.         psz_source = strdup( cd_drives[0] );
  748.         cdio_free_device_list( cd_drives );
  749.       }
  750.     }
  751.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
  752.                "source=%s entry=%d type=%d",
  753.                psz_source, p_itemid->num, p_itemid->type);
  754.     return psz_source;
  755. }
  756. /*
  757.    Set's start origin subsequent seeks/reads
  758. */
  759. static void
  760. VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
  761.               lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
  762. {
  763.   thread_vcd_data_t * p_vcd  = (thread_vcd_data_t *) p_input->p_access_data;
  764.   p_vcd->origin_lsn = origin_lsn;
  765.   p_vcd->cur_lsn    = cur_lsn;
  766.   p_vcd->end_lsn    = end_lsn;
  767.   p_vcd->cur_track  = cur_track;
  768.   p_vcd->play_item.num  = cur_entry;
  769.   p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
  770.   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
  771.              "origin: %lu, cur_lsn: %lu, end_lsn: %lu, entry: %d, track: %d",
  772.              (long unsigned int) origin_lsn, 
  773.      (long unsigned int) cur_lsn, 
  774.      (long unsigned int) end_lsn, cur_entry, cur_track );
  775.   p_input->stream.p_selected_area->i_tell =
  776.     (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
  777.   VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
  778.                 "chapter", 
  779. p_vcd->play_item.type == VCDINFO_ITEM_TYPE_ENTRY ?
  780. _("Entry") : _("Segment"), 
  781. "Setting entry/segment");
  782. }
  783. /*****************************************************************************
  784.  * vcd_Open: Opens a VCD device or file and returns an opaque handle
  785.  *****************************************************************************/
  786. static vcdinfo_obj_t *
  787. vcd_Open( vlc_object_t *p_this, const char *psz_dev )
  788. {
  789.     vcdinfo_obj_t *p_vcdobj;
  790.     char  *actual_dev;
  791.     if( !psz_dev ) return NULL;
  792.     actual_dev=strdup(psz_dev);
  793.     if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
  794.          VCDINFO_OPEN_VCD) {
  795.       free(actual_dev);
  796.       return NULL;
  797.     }
  798.     free(actual_dev);
  799.     return p_vcdobj;
  800. }
  801. /****************************************************************************
  802.  * VCDReadSector: Read a sector (2324 bytes)
  803.  ****************************************************************************/
  804. static int
  805. VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
  806.                lsn_t cur_lsn, byte_t * p_buffer )
  807. {
  808.   typedef struct {
  809.     uint8_t subheader   [8];
  810.     uint8_t data        [M2F2_SECTOR_SIZE];
  811.     uint8_t spare       [4];
  812.   } vcdsector_t;
  813.   vcdsector_t vcd_sector;
  814.   if( cdio_read_mode2_sector( vcdinfo_get_cd_image( p_vcd ),
  815.                               &vcd_sector, cur_lsn, VLC_TRUE )
  816.       != 0)
  817.   {
  818.       msg_Warn( p_this, "Could not read LSN %lu", 
  819. (long unsigned int) cur_lsn );
  820.       return -1;
  821.   }
  822.   memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
  823.   return( 0 );
  824. }
  825. /****************************************************************************
  826.  Update the "varname" variable to i_num without triggering a callback.
  827. ****************************************************************************/
  828. static void
  829. VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
  830.               const char *p_varname, char *p_label, 
  831.       const char *p_debug_label)
  832. {
  833.   vlc_value_t val;
  834.   val.i_int = i_num;
  835.   if (NULL != p_vcd_input) {
  836.     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
  837.     dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
  838.   }
  839.   if (p_label) {
  840.     vlc_value_t text;
  841.     text.psz_string = p_label;
  842.     var_Change( p_input, p_varname, VLC_VAR_SETTEXT, &text, NULL );
  843.   }
  844.   var_Change( p_input, p_varname, i_action, &val, NULL );
  845. }
  846. static inline void
  847. MetaInfoAddStr(input_thread_t *p_input, char *p_cat,
  848.                char *title, const char *str)
  849. {
  850.   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
  851.   if ( str ) {
  852.     dbg_print( INPUT_DBG_META, "field: %s: %sn", title, str);
  853.     input_Control( p_input, INPUT_ADD_INFO, p_cat, title, "%s", str);
  854.   }
  855. }
  856. static inline void
  857. MetaInfoAddNum(input_thread_t *p_input, char *p_cat, char *title, int num)
  858. {
  859.   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
  860.   dbg_print( INPUT_DBG_META, "field %s: %dn", title, num);
  861.   input_Control( p_input, INPUT_ADD_INFO, p_cat, title, "%d", num );
  862. }
  863. #define addstr(title, str) 
  864.   MetaInfoAddStr( p_input, p_cat, title, str );
  865. #define addnum(title, num) 
  866.   MetaInfoAddNum( p_input, p_cat, title, num );
  867. static void InformationCreate( input_thread_t *p_input  )
  868. {
  869.   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
  870.   unsigned int i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
  871.   unsigned int last_entry = 0;
  872.   char *p_cat;
  873.   track_t i_track;
  874.   p_cat = _("General");
  875.   addstr( _("VCD Format"),  vcdinfo_get_format_version_str(p_vcd->vcd) );
  876.   addstr( _("Album"),       vcdinfo_get_album_id(p_vcd->vcd));
  877.   addstr( _("Application"), vcdinfo_get_application_id(p_vcd->vcd) );
  878.   addstr( _("Preparer"),    vcdinfo_get_preparer_id(p_vcd->vcd) );
  879.   addnum( _("Vol #"),       vcdinfo_get_volume_num(p_vcd->vcd) );
  880.   addnum( _("Vol max #"),   vcdinfo_get_volume_count(p_vcd->vcd) );
  881.   addstr( _("Volume Set"),  vcdinfo_get_volumeset_id(p_vcd->vcd) );
  882.   addstr( _("Volume"),      vcdinfo_get_volume_id(p_vcd->vcd) );
  883.   addstr( _("Publisher"),   vcdinfo_get_publisher_id(p_vcd->vcd) );
  884.   addstr( _("System Id"),   vcdinfo_get_system_id(p_vcd->vcd) );
  885.   addnum( "LIDs",           vcdinfo_get_num_LIDs(p_vcd->vcd) );
  886.   addnum( _("Entries"),     vcdinfo_get_num_entries(p_vcd->vcd) );
  887.   addnum( _("Segments"),    vcdinfo_get_num_segments(p_vcd->vcd) );
  888.   addnum( _("Tracks"),      vcdinfo_get_num_tracks(p_vcd->vcd) );
  889.   /* Spit out track information. Could also include MSF info.
  890.    */
  891. #define TITLE_MAX 30
  892.   for( i_track = 1 ; i_track < p_vcd->num_tracks ; i_track++ ) {
  893.     char psz_track[TITLE_MAX];
  894.     unsigned int audio_type = vcdinfo_get_track_audio_type(p_vcd->vcd, 
  895.    i_track);
  896.     snprintf(psz_track, TITLE_MAX, "%s%02d", _("Track "), i_track);
  897.     p_cat = psz_track;
  898.     if (p_vcd->b_svd) {
  899.       addnum(_("Audio Channels"),  
  900.      vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type) );
  901.     }
  902.     addnum(_("First Entry Point"), last_entry );
  903.     for ( ; last_entry < i_nb 
  904.     && vcdinfo_get_track(p_vcd->vcd, last_entry) == i_track;
  905.   last_entry++ ) ;
  906.     addnum(_("Last Entry Point"), last_entry-1 );
  907.   }
  908. }
  909. #define add_format_str_info(val)        
  910.   {        
  911.     const char *str = val;        
  912.     unsigned int len;        
  913.     if (val != NULL) {        
  914.       len=strlen(str);        
  915.       if (len != 0) {        
  916.         strncat(tp, str, TEMP_STR_LEN-(tp-temp_str));        
  917.         tp += len;        
  918.       }                                                        
  919.       saw_control_prefix = VLC_FALSE;        
  920.     }        
  921.   }
  922. #define add_format_num_info( val, fmt )        
  923.   {        
  924.     char num_str[10];        
  925.     unsigned int len;        
  926.     sprintf(num_str, fmt, val);                                
  927.     len = strlen(num_str);        
  928.     if( len != 0 )                                             
  929.     {                        
  930.       strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));        
  931.       tp += len;        
  932.     }        
  933.     saw_control_prefix = VLC_FALSE;                                
  934.   }
  935. /*!
  936.    Take a format string and expand escape sequences, that is sequences that
  937.    begin with %, with information from the current VCD.
  938.    The expanded string is returned. Here is a list of escape sequences:
  939.    %A : The album information
  940.    %C : The VCD volume count - the number of CD's in the collection.
  941.    %c : The VCD volume num - the number of the CD in the collection.
  942.    %F : The VCD Format, e.g. VCD 1.0, VCD 1.1, VCD 2.0, or SVCD
  943.    %I : The current entry/segment/playback type, e.g. ENTRY, TRACK, SEGMENT...
  944.    %L : The playlist ID prefixed with " LID" if it exists
  945.    %M : MRL
  946.    %N : The current number of the %I - a decimal number
  947.    %P : The publisher ID
  948.    %p : The preparer ID
  949.    %S : If we are in a segment (menu), the kind of segment
  950.    %T : The track number
  951.    %V : The volume set ID
  952.    %v : The volume ID
  953.        A number between 1 and the volume count.
  954.    %% : a %
  955. */
  956. static char *
  957. VCDFormatStr(const input_thread_t *p_input, thread_vcd_data_t *p_vcd,
  958.              const char format_str[], const char *mrl,
  959.              const vcdinfo_itemid_t *itemid)
  960. {
  961. #define TEMP_STR_SIZE 256
  962. #define TEMP_STR_LEN (TEMP_STR_SIZE-1)
  963.   static char    temp_str[TEMP_STR_SIZE];
  964.   size_t         i;
  965.   char *         tp = temp_str;
  966.   vlc_bool_t     saw_control_prefix = VLC_FALSE;
  967.   size_t         format_len = strlen(format_str);
  968.   memset(temp_str, 0, TEMP_STR_SIZE);
  969.   for (i=0; i<format_len; i++) {
  970.     if (!saw_control_prefix && format_str[i] != '%') {
  971.       *tp++ = format_str[i];
  972.       saw_control_prefix = VLC_FALSE;
  973.       continue;
  974.     }
  975.     switch(format_str[i]) {
  976.     case '%':
  977.       if (saw_control_prefix) {
  978.         *tp++ = '%';
  979.       }
  980.       saw_control_prefix = !saw_control_prefix;
  981.       break;
  982.     case 'A':
  983.       add_format_str_info(vcdinfo_strip_trail(vcdinfo_get_album_id(p_vcd->vcd),
  984.                                               MAX_ALBUM_LEN));
  985.       break;
  986.     case 'c':
  987.       add_format_num_info(vcdinfo_get_volume_num(p_vcd->vcd), "%d");
  988.       break;
  989.     case 'C':
  990.       add_format_num_info(vcdinfo_get_volume_count(p_vcd->vcd), "%d");
  991.       break;
  992.     case 'F':
  993.       add_format_str_info(vcdinfo_get_format_version_str(p_vcd->vcd));
  994.       break;
  995.     case 'I':
  996.       {
  997.         switch (itemid->type) {
  998.         case VCDINFO_ITEM_TYPE_TRACK:
  999.           strncat(tp, _("Track"), TEMP_STR_LEN-(tp-temp_str));
  1000.           tp += strlen(_("Track"));
  1001.         break;
  1002.         case VCDINFO_ITEM_TYPE_ENTRY:
  1003.           strncat(tp, _("Entry"), TEMP_STR_LEN-(tp-temp_str));
  1004.           tp += strlen(_("Entry"));
  1005.           break;
  1006.         case VCDINFO_ITEM_TYPE_SEGMENT:
  1007.           strncat(tp, _("Segment"), TEMP_STR_LEN-(tp-temp_str));
  1008.           tp += strlen(_("Segment"));
  1009.           break;
  1010.         case VCDINFO_ITEM_TYPE_LID:
  1011.           strncat(tp, _("List ID"), TEMP_STR_LEN-(tp-temp_str));
  1012.           tp += strlen(_("List ID"));
  1013.           break;
  1014.         case VCDINFO_ITEM_TYPE_SPAREID2:
  1015.           strncat(tp, _("Navigation"), TEMP_STR_LEN-(tp-temp_str));
  1016.           tp += strlen(_("Navigation"));
  1017.           break;
  1018.         default:
  1019.           /* What to do? */
  1020.           ;
  1021.         }
  1022.         saw_control_prefix = VLC_FALSE;
  1023.       }
  1024.       break;
  1025.     case 'L':
  1026.       if (vcdplayer_pbc_is_on(p_vcd)) {
  1027.         char num_str[40];
  1028.         sprintf(num_str, "%s %d", _("List ID"), p_vcd->cur_lid);
  1029.         strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));
  1030.         tp += strlen(num_str);
  1031.       }
  1032.       saw_control_prefix = VLC_FALSE;
  1033.       break;
  1034.     case 'M':
  1035.       add_format_str_info(mrl);
  1036.       break;
  1037.     case 'N':
  1038.       add_format_num_info(itemid->num, "%d");
  1039.       break;
  1040.     case 'p':
  1041.       add_format_str_info(vcdinfo_get_preparer_id(p_vcd->vcd));
  1042.       break;
  1043.     case 'P':
  1044.       add_format_str_info(vcdinfo_get_publisher_id(p_vcd->vcd));
  1045.       break;
  1046.     case 'S':
  1047.       if ( VCDINFO_ITEM_TYPE_SEGMENT==itemid->type ) {
  1048.         char seg_type_str[10];
  1049.         sprintf(seg_type_str, " %s",
  1050.                 vcdinfo_video_type2str(p_vcd->vcd, itemid->num));
  1051.         strncat(tp, seg_type_str, TEMP_STR_LEN-(tp-temp_str));
  1052.         tp += strlen(seg_type_str);
  1053.       }
  1054.       saw_control_prefix = VLC_FALSE;
  1055.       break;
  1056.     case 'T':
  1057.       add_format_num_info(p_vcd->cur_track, "%d");
  1058.       break;
  1059.     case 'V':
  1060.       add_format_str_info(vcdinfo_get_volumeset_id(p_vcd->vcd));
  1061.       break;
  1062.     case 'v':
  1063.       add_format_str_info(vcdinfo_get_volume_id(p_vcd->vcd));
  1064.       break;
  1065.     default:
  1066.       *tp++ = '%';
  1067.       *tp++ = format_str[i];
  1068.       saw_control_prefix = VLC_FALSE;
  1069.     }
  1070.   }
  1071.   return strdup(temp_str);
  1072. }
  1073. static void
  1074. VCDCreatePlayListItem(const input_thread_t *p_input,
  1075.                       thread_vcd_data_t *p_vcd,
  1076.                       playlist_t *p_playlist,
  1077.                       const vcdinfo_itemid_t *itemid,
  1078.                       char *psz_mrl, int psz_mrl_max,
  1079.                       const char *psz_source, int playlist_operation,
  1080.                       int i_pos)
  1081. {
  1082.   char *p_author;
  1083.   char *p_title;
  1084.   char c_type;
  1085.   switch(itemid->type) {
  1086.   case VCDINFO_ITEM_TYPE_TRACK:
  1087.     c_type='T';
  1088.     break;
  1089.   case VCDINFO_ITEM_TYPE_SEGMENT:
  1090.     c_type='S';
  1091.     break;
  1092.   case VCDINFO_ITEM_TYPE_LID:
  1093.     c_type='P';
  1094.     break;
  1095.   case VCDINFO_ITEM_TYPE_ENTRY:
  1096.     c_type='E';
  1097.     break;
  1098.   default:
  1099.     c_type='?';
  1100.     break;
  1101.   }
  1102.   snprintf(psz_mrl, psz_mrl_max, "%s%s@%c%u", VCD_MRL_PREFIX, psz_source,
  1103.            c_type, itemid->num);
  1104.   p_title =
  1105.     VCDFormatStr( p_input, p_vcd,
  1106.   config_GetPsz( p_input, MODULE_STRING "-title-format" ),
  1107.   psz_mrl, itemid );
  1108.   
  1109.   playlist_Add( p_playlist, psz_mrl, p_title, playlist_operation, i_pos );
  1110.   p_author =
  1111.     VCDFormatStr( p_input, p_vcd,
  1112.   config_GetPsz( p_input, MODULE_STRING "-author-format" ),
  1113.   psz_mrl, itemid );
  1114.   if( i_pos == PLAYLIST_END ) i_pos = p_playlist->i_size - 1;
  1115.   playlist_AddInfo(p_playlist, i_pos, _("General"), _("Author"), "%s",
  1116.    p_author);
  1117. }
  1118. static int
  1119. VCDFixupPlayList( input_thread_t *p_input, thread_vcd_data_t *p_vcd,
  1120.                   const char *psz_source, vcdinfo_itemid_t *itemid,
  1121.                   vlc_bool_t play_single_item )
  1122. {
  1123.   unsigned int i;
  1124.   playlist_t * p_playlist;
  1125.   char       * psz_mrl;
  1126.   unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) +
  1127.     strlen("@T") + strlen("100") + 1;
  1128.   psz_mrl = malloc( psz_mrl_max );
  1129.   if( psz_mrl == NULL )
  1130.     {
  1131.       msg_Warn( p_input, "out of memory" );
  1132.       return -1;
  1133.     }
  1134.   p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
  1135.                                                FIND_ANYWHERE );
  1136.   if( !p_playlist )
  1137.     {
  1138.       msg_Warn( p_input, "can't find playlist" );
  1139.       free(psz_mrl);
  1140.       return -1;
  1141.     }
  1142.   if ( play_single_item ) 
  1143.     {
  1144.     /* May fill out more information when the playlist user interface becomes
  1145.        more mature.
  1146.      */
  1147.     VCDCreatePlayListItem(p_input, p_vcd, p_playlist, itemid,
  1148.                           psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE,
  1149.                           p_playlist->i_index);
  1150.     } 
  1151.   else 
  1152.     {
  1153.     vcdinfo_itemid_t list_itemid;
  1154.     list_itemid.type=VCDINFO_ITEM_TYPE_ENTRY;
  1155.     playlist_Delete( p_playlist, p_playlist->i_index);
  1156.     for( i = 0 ; i < p_vcd->num_entries ; i++ )
  1157.       {
  1158.         list_itemid.num=i;
  1159.         VCDCreatePlayListItem(p_input, p_vcd, p_playlist, &list_itemid,
  1160.                               psz_mrl, psz_mrl_max, psz_source,
  1161.                               PLAYLIST_APPEND, PLAYLIST_END);
  1162.       }
  1163.     playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
  1164.   }
  1165.   vlc_object_release( p_playlist );
  1166.   free(psz_mrl);
  1167.   return 0;
  1168. }
  1169. /*****************************************************************************
  1170.  * Public routines.
  1171.  *****************************************************************************/
  1172. int
  1173. E_(DebugCallback)   ( vlc_object_t *p_this, const char *psz_name,
  1174.                       vlc_value_t oldval, vlc_value_t val, void *p_data )
  1175. {
  1176.   thread_vcd_data_t *p_vcd;
  1177.   if (NULL == p_vcd_input) return VLC_EGENERIC;
  1178.   p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
  1179.   if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
  1180.     msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
  1181.              p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
  1182.   }
  1183.   p_vcd->i_debug = val.i_int;
  1184.   return VLC_SUCCESS;
  1185. }
  1186. /*
  1187.   The front-ends change spu-es - which sort of represents a symbolic
  1188.   name. Internally we use spu-channel which runs from 0..3.
  1189.   So we add a callback to intercept changes to spu-es and change them
  1190.   to updates to spu-channel. Ugly.
  1191. */
  1192. static int 
  1193. VCDSPUCallback( vlc_object_t *p_this, const char *psz_variable,
  1194.                 vlc_value_t old_val, vlc_value_t new_val, void *param)
  1195. {
  1196.   input_thread_t    *p_input = (input_thread_t *)p_this;
  1197.   thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
  1198.   vlc_value_t val;
  1199.   
  1200.   dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EVENT), "old_val: %x, new_val %x", 
  1201.      old_val.i_int, new_val.i_int);
  1202.   val.i_int =  new_val.i_int;
  1203.   var_Set( p_this, "spu-channel", val );
  1204.   
  1205.   return VLC_SUCCESS;
  1206. }
  1207. /*****************************************************************************
  1208.   Open: open VCD.
  1209.   read in meta-information about VCD: the number of tracks, segments,
  1210.   entries, size and starting information. Then set up state variables so
  1211.   that we read/seek starting at the location specified.
  1212.   On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
  1213.   and VLC_EGENERIC for some other error.
  1214.  *****************************************************************************/
  1215. int
  1216. E_(Open) ( vlc_object_t *p_this )
  1217. {
  1218.     input_thread_t *        p_input = (input_thread_t *)p_this;
  1219.     thread_vcd_data_t *     p_vcd;
  1220.     char *                  psz_source;
  1221.     vcdinfo_itemid_t        itemid;
  1222.     vlc_bool_t              b_play_ok;
  1223.     vlc_bool_t              play_single_item = VLC_FALSE;
  1224.     p_input->pf_read        = VCDRead;
  1225.     p_input->pf_seek        = VCDSeek;
  1226.     p_input->pf_set_area    = VCDSetArea;
  1227.     p_input->pf_set_program = VCDSetProgram;
  1228.     p_vcd = malloc( sizeof(thread_vcd_data_t) );
  1229.     if( p_vcd == NULL )
  1230.     {
  1231.         LOG_ERR ("out of memory" );
  1232.         return VLC_ENOMEM;
  1233.     }
  1234.     p_input->p_access_data = (void *)p_vcd;
  1235.     p_vcd->i_debug         = config_GetInt( p_this, MODULE_STRING "-debug" );
  1236.     p_vcd->in_still        = VLC_FALSE;
  1237.     p_vcd->play_item.type  = VCDINFO_ITEM_TYPE_NOTFOUND;
  1238.     /* Set where to log errors messages from libcdio. */
  1239.     p_vcd_input = (input_thread_t *)p_this;
  1240.     cdio_log_set_handler ( cdio_log_handler );
  1241.     vcd_log_set_handler ( vcd_log_handler );
  1242.     psz_source = VCDParse( p_input, &itemid, &play_single_item );
  1243.     if ( NULL == psz_source )
  1244.     {
  1245.       free( p_vcd );
  1246.       return( VLC_EGENERIC );
  1247.     }
  1248.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
  1249.                psz_source, p_input->psz_name );
  1250.     p_vcd->p_segments = NULL;
  1251.     p_vcd->p_entries  = NULL;
  1252.     /* set up input  */
  1253.     p_input->i_mtu = VCD_DATA_ONCE;
  1254.     vlc_mutex_lock( &p_input->stream.stream_lock );
  1255.     /* If we are here we can control the pace... */
  1256.     p_input->stream.b_pace_control = 1;
  1257.     p_input->stream.b_seekable = 1;
  1258.     p_input->stream.p_selected_area->i_size = 0;
  1259.     p_input->stream.p_selected_area->i_tell = 0;
  1260.     vlc_mutex_unlock( &p_input->stream.stream_lock );
  1261.     if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
  1262.     {
  1263.         msg_Warn( p_input, "could not open %s", psz_source );
  1264.         goto err_exit;
  1265.     }
  1266.     p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
  1267.     
  1268.     /* Get track information. */
  1269.     p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
  1270.                                             vcdinfo_get_cd_image(p_vcd->vcd),
  1271.                                             &p_vcd->p_sectors );
  1272.     if( p_vcd->num_tracks < 0 )
  1273.         LOG_ERR ("unable to count tracks" );
  1274.     else if( p_vcd->num_tracks <= 1 )
  1275.         LOG_ERR ("no movie tracks found" );
  1276.     if( p_vcd->num_tracks <= 1)
  1277.     {
  1278.         vcdinfo_close( p_vcd->vcd );
  1279.         goto err_exit;
  1280.     }
  1281.     /* Set stream and area data */
  1282.     vlc_mutex_lock( &p_input->stream.stream_lock );
  1283.     /* Initialize ES structures */
  1284.     input_InitStream( p_input, sizeof( stream_ps_data_t ) );
  1285.     /* disc input method */
  1286.     p_input->stream.i_method = INPUT_METHOD_VCD;
  1287.     p_input->stream.i_area_nb = 1;
  1288.     /* Initialize segment information. */
  1289.     VCDSegments( p_input );
  1290.     /* Initialize track area information. */
  1291.     VCDTracks( p_input );
  1292.     if( VCDEntryPoints( p_input ) < 0 )
  1293.     {
  1294.         msg_Warn( p_input, "could not read entry points, will not use them" );
  1295.         p_vcd->b_valid_ep = VLC_FALSE;
  1296.     }
  1297.     if( VCDLIDs( p_input ) < 0 )
  1298.     {
  1299.         msg_Warn( p_input, "could not read entry LIDs" );
  1300.     }
  1301.     b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
  1302.     vlc_mutex_unlock( &p_input->stream.stream_lock );
  1303.     if ( ! b_play_ok ) {
  1304.       vcdinfo_close( p_vcd->vcd );
  1305.       goto err_exit;
  1306.     }
  1307.     if( !p_input->psz_demux || !*p_input->psz_demux )
  1308.     {
  1309. #if FIXED
  1310.       p_input->psz_demux = "vcdx";
  1311. #else
  1312.       p_input->psz_demux = "ps";
  1313. #endif
  1314.     }
  1315.     p_vcd->p_intf = intf_Create( p_input, "vcdx" );
  1316.     p_vcd->p_intf->b_block = VLC_FALSE;
  1317.     intf_RunThread( p_vcd->p_intf );
  1318.     InformationCreate( p_input );
  1319.     if (play_single_item)
  1320.       VCDFixupPlayList( p_input, p_vcd, psz_source, &itemid, 
  1321. play_single_item );
  1322.     free( psz_source );
  1323.     var_AddCallback( p_this, "spu-es", VCDSPUCallback, NULL );
  1324.     return VLC_SUCCESS;
  1325.  err_exit:
  1326.     free( psz_source );
  1327.     free( p_vcd );
  1328.     return VLC_EGENERIC;
  1329. }
  1330. /*****************************************************************************
  1331.  * Close: closes VCD releasing allocated memory.
  1332.  *****************************************************************************/
  1333. void
  1334. E_(Close) ( vlc_object_t *p_this )
  1335. {
  1336.     input_thread_t *   p_input = (input_thread_t *)p_this;
  1337.     thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
  1338.     dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
  1339.     var_DelCallback( p_this, "spu-es", VCDSPUCallback, NULL );
  1340.     vcdinfo_close( p_vcd->vcd );
  1341.     free( p_vcd->p_entries );
  1342.     free( p_vcd->p_segments );
  1343.     free( p_vcd->p_sectors );
  1344.     /* For reasons that are a mystery to me we don't have to deal with
  1345.        stopping, and destroying the p_vcd->p_intf thread. And if we do
  1346.        it causes problems upstream.
  1347.      */
  1348.     if( p_vcd->p_intf != NULL )
  1349.     {
  1350.         p_vcd->p_intf = NULL;
  1351.     }
  1352.     free( p_vcd );
  1353.     p_input->p_access_data = NULL;
  1354.     p_vcd_input = NULL;
  1355. }