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

midi

开发平台:

Unix_Linux

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