+/*!
+ Set reading to play an entire track.
+*/
+static void
+_vcdplayer_set_track(access_t * p_access, track_t i_track)
+{
+ vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
+ if (i_track < 1 || i_track > p_vcdplayer->i_tracks)
+ return;
+ else {
+ const vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
+ vcdinfo_itemid_t itemid;
+
+ itemid.num = i_track;
+ itemid.type = VCDINFO_ITEM_TYPE_TRACK;
+ p_vcdplayer->in_still = 0;
+
+ VCDSetOrigin(p_access, vcdinfo_get_track_lsn(p_vcdinfo, i_track),
+ i_track, &itemid);
+
+ dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
+ }
+}
+
+/*!
+ Set reading to play an entry
+*/
+static void
+_vcdplayer_set_entry(access_t * p_access, unsigned int num)
+{
+ vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
+ vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
+ const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
+
+ if (num >= i_entries) {
+ LOG_ERR("%s %d", "bad entry number", num);
+ return;
+ } else {
+ vcdinfo_itemid_t itemid;
+
+ itemid.num = num;
+ itemid.type = VCDINFO_ITEM_TYPE_ENTRY;
+ p_vcdplayer->i_still = 0;
+
+ VCDSetOrigin(p_access, vcdinfo_get_entry_lsn(p_vcdinfo, num),
+ vcdinfo_get_track(p_vcdinfo, num), &itemid);
+
+ dbg_print(INPUT_DBG_LSN, "LSN: %u, track_end LSN: %u",
+ p_vcdplayer->i_lsn, p_vcdplayer->track_end_lsn);
+ }
+}
+
+/*!
+ Set reading to play an segment (e.g. still frame)
+*/
+static void
+_vcdplayer_set_segment(access_t * p_access, unsigned int num)
+{
+ vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
+ vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
+ segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
+
+ if (num >= i_segs) {
+ LOG_ERR("%s %d", "bad segment number", num);
+ return;
+ } else {
+ vcdinfo_itemid_t itemid;
+
+ if (VCDINFO_NULL_LSN==p_vcdplayer->i_lsn) {
+ LOG_ERR("%s %d",
+ "Error in getting current segment number", num);
+ return;
+ }
+
+ itemid.num = num;
+ itemid.type = VCDINFO_ITEM_TYPE_SEGMENT;
+
+ VCDSetOrigin(p_access, vcdinfo_get_seg_lsn(p_vcdinfo, num), 0, &itemid);
+
+ dbg_print(INPUT_DBG_LSN, "LSN: %u", p_vcdplayer->i_lsn);
+ }
+}
+
+/* Play entry. */
+/* Play a single item. */
+static bool
+vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
+{
+ vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
+ vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
+
+ dbg_print(INPUT_DBG_CALL, "called itemid.num: %d, itemid.type: %d",
+ itemid.num, itemid.type);
+
+ p_vcdplayer->i_still = 0;
+
+ switch (itemid.type) {
+ case VCDINFO_ITEM_TYPE_SEGMENT:
+ {
+ vcdinfo_video_segment_type_t segtype
+ = vcdinfo_get_video_type(p_vcdinfo, itemid.num);
+ segnum_t i_segs = vcdinfo_get_num_segments(p_vcdinfo);
+
+ dbg_print(INPUT_DBG_PBC, "%s (%d), itemid.num: %d",
+ vcdinfo_video_type2str(p_vcdinfo, itemid.num),
+ (int) segtype, itemid.num);
+
+ if (itemid.num >= i_segs) return false;
+ _vcdplayer_set_segment(p_access, itemid.num);
+
+ switch (segtype)
+ {
+ case VCDINFO_FILES_VIDEO_NTSC_STILL:
+ case VCDINFO_FILES_VIDEO_NTSC_STILL2:
+ case VCDINFO_FILES_VIDEO_PAL_STILL:
+ case VCDINFO_FILES_VIDEO_PAL_STILL2:
+ p_vcdplayer->i_still = STILL_READING;
+ break;
+ default:
+ p_vcdplayer->i_still = 0;
+ }
+
+ break;
+ }
+
+ case VCDINFO_ITEM_TYPE_TRACK:
+ dbg_print(INPUT_DBG_PBC, "track %d", itemid.num);
+ if (itemid.num < 1 || itemid.num > p_vcdplayer->i_tracks) return false;
+ _vcdplayer_set_track(p_access, itemid.num);
+ break;
+
+ case VCDINFO_ITEM_TYPE_ENTRY:
+ {
+ unsigned int i_entries = vcdinfo_get_num_entries(p_vcdinfo);
+ dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num);
+ if (itemid.num >= i_entries) return false;
+ _vcdplayer_set_entry(p_access, itemid.num);
+ break;
+ }
+
+ case VCDINFO_ITEM_TYPE_LID:
+ LOG_ERR("%s", "Should have converted p_vcdplayer above");
+ return false;
+ break;
+
+ case VCDINFO_ITEM_TYPE_NOTFOUND:
+ dbg_print(INPUT_DBG_PBC, "play nothing");
+ p_vcdplayer->i_lsn = p_vcdplayer->end_lsn;
+ return false;
+
+ default:
+ LOG_ERR("item type %d not implemented.", itemid.type);
+ return false;
+ }
+
+ p_vcdplayer->play_item = itemid;
+
+ /* Some players like xine, have a fifo queue of audio and video buffers
+ that need to be flushed when playing a new selection. */
+ /* if (p_vcdplayer->flush_buffers)
+ p_vcdplayer->flush_buffers(); */
+ return true;
+}
+
+/*
+ Set's start origin and size for subsequent seeks.
+ input: p_vcdplayer->i_lsn, p_vcdplayer->play_item
+ changed: p_vcdplayer->origin_lsn, p_vcdplayer->end_lsn
+*/
+
+/* FIXME: add parameters lsn, i_track, p_itemid and set accordingly. */
+void
+vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track,
+ const vcdinfo_itemid_t *p_itemid)
+{
+ vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
+ const size_t i_size= vcdplayer_get_item_size(p_access, *p_itemid);
+
+ p_vcdplayer->play_item.num = p_itemid->num;
+ p_vcdplayer->play_item.type = p_itemid->type;
+ p_vcdplayer->i_lsn = i_lsn;
+ p_vcdplayer->end_lsn = p_vcdplayer->i_lsn + i_size;
+ p_vcdplayer->origin_lsn = p_vcdplayer->i_lsn;
+ p_vcdplayer->i_track = i_track;
+ p_vcdplayer->track_lsn = vcdinfo_get_track_lsn(p_vcdplayer->vcd,
+ i_track);
+ p_vcdplayer->track_end_lsn = p_vcdplayer->track_lsn +
+ vcdinfo_get_track_sect_count(p_vcdplayer->vcd, i_track);
+
+ dbg_print((INPUT_DBG_CALL|INPUT_DBG_LSN),
+ "lsn %u, end LSN: %u item.num %d, item.type %d",
+ p_vcdplayer->i_lsn, p_vcdplayer->end_lsn,
+ p_vcdplayer->play_item.num, p_vcdplayer->play_item.type);
+}
+
+/*!
+ Get the next play-item in the list given in the LIDs. Note play-item
+ here refers to list of play-items for a single LID It shouldn't be
+ confused with a user's list of favorite things to play or the
+ "next" field of a LID which moves us to a different LID.
+ */
+static bool
+vcdplayer_inc_play_item(access_t *p_access)
+{
+
+ vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
+ int noi;
+
+ dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcdplayer->pdi);
+
+ if ( NULL == p_vcdplayer || NULL == p_vcdplayer->pxd.pld ) return false;
+
+ noi = vcdinf_pld_get_noi(p_vcdplayer->pxd.pld);
+
+ if ( noi <= 0 ) return false;
+
+ /* Handle delays like autowait or wait here? */
+
+ p_vcdplayer->pdi++;
+
+ if ( p_vcdplayer->pdi < 0 || p_vcdplayer->pdi >= noi ) return false;
+
+ else {
+ uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcdplayer->pxd.pld,
+ p_vcdplayer->pdi);
+ vcdinfo_itemid_t trans_itemid;
+
+ if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
+
+ vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
+ dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
+ p_vcdplayer->pdi, vcdinfo_pin2str (trans_itemid_num));
+ return vcdplayer_play_single_item(p_access, trans_itemid);
+ }
+}
+
+void
+vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid)
+{
+ vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_access->p_sys;
+
+ dbg_print(INPUT_DBG_CALL, "called itemid.num: %d itemid.type: %d",
+ itemid.num, itemid.type);
+
+ if (!vcdplayer_pbc_is_on(p_vcdplayer)) {
+ vcdplayer_play_single_item(p_access, itemid);
+ } else {
+ /* PBC on - Itemid.num is LID. */
+
+ vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd;
+
+ if (p_vcdinfo == NULL) return;
+
+ p_vcdplayer->i_lid = itemid.num;
+ vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), itemid.num);
+
+ switch (p_vcdplayer->pxd.descriptor_type) {
+
+ case PSD_TYPE_SELECTION_LIST:
+ case PSD_TYPE_EXT_SELECTION_LIST: {
+ vcdinfo_itemid_t trans_itemid;
+ uint16_t trans_itemid_num;
+
+ if (p_vcdplayer->pxd.psd == NULL) return;
+ trans_itemid_num = vcdinf_psd_get_itemid(p_vcdplayer->pxd.psd);
+ vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
+ p_vcdplayer->i_loop = 1;
+ p_vcdplayer->loop_item = trans_itemid;
+ vcdplayer_play_single_item(p_access, trans_itemid);
+ break;
+ }
+
+ case PSD_TYPE_PLAY_LIST: {
+ if (p_vcdplayer->pxd.pld == NULL) return;
+ p_vcdplayer->pdi = -1;
+ vcdplayer_inc_play_item(p_access);
+ break;
+ }
+
+ case PSD_TYPE_END_LIST:
+ case PSD_TYPE_COMMAND_LIST:
+
+ default:
+ ;
+ }
+ }
+}