X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fvcdx%2Fvcdplayer.c;h=8374f28ed66690bb1e76a5d0f8c939a2350e30ca;hb=812558533ce231d378bde58aa5f5061b10856b69;hp=f47ddb00fa40a55fa3115b0915fe5c50017fa6b6;hpb=fd05dc698e736455dfa075fdb93f3600365f4e9d;p=vlc diff --git a/modules/access/vcdx/vcdplayer.c b/modules/access/vcdx/vcdplayer.c index f47ddb00fa..8374f28ed6 100644 --- a/modules/access/vcdx/vcdplayer.c +++ b/modules/access/vcdx/vcdplayer.c @@ -2,8 +2,8 @@ * vcdplayer.c : VCD input module for vlc * using libcdio, libvcd and libvcdinfo ***************************************************************************** - * Copyright (C) 2003 Rocky Bernstein - * $Id: vcdplayer.c,v 1.1 2003/10/04 18:55:13 gbazin Exp $ + * Copyright (C) 2003, 2004 Rocky Bernstein + * $Id$ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,9 +31,11 @@ #include #include +#include #include "vcd.h" #include "vcdplayer.h" +#include "intf.h" #include @@ -41,83 +43,60 @@ #include #include +extern void VCDSetOrigin ( access_t *p_access, lsn_t i_lsn, track_t i_track, + const vcdinfo_itemid_t * p_itemid ); + /*! Return true if playback control (PBC) is on */ -bool -vcdplayer_pbc_is_on(const thread_vcd_data_t *p_vcd) +bool +vcdplayer_pbc_is_on( const vcdplayer_t *p_vcdplayer ) { - return VCDINFO_INVALID_ENTRY != p_vcd->cur_lid; + return VCDINFO_INVALID_ENTRY != p_vcdplayer->i_lid; } -lid_t -vcdplayer_selection2lid ( input_thread_t *p_input, int entry_num ) +/* Given an itemid, return the size for the object (via information + previously stored when opening the vcd). */ +static size_t +vcdplayer_get_item_size(access_t * p_access, vcdinfo_itemid_t itemid) { - /* FIXME: Some of this probably gets moved to vcdinfo. */ - /* Convert selection number to lid and then entry number...*/ - thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data; - unsigned int offset; - unsigned int bsn=vcdinf_get_bsn(p_vcd->pxd.psd); - vcdinfo_obj_t *obj = p_vcd->vcd; - - dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), - "Called lid %u, entry_num %d bsn %d", p_vcd->cur_lid, - entry_num, bsn); - - if ( (entry_num - bsn + 1) > 0) { - offset = vcdinfo_lid_get_offset(obj, p_vcd->cur_lid, entry_num-bsn+1); - } else { - LOG_ERR( "Selection number %u too small. bsn %u", entry_num, bsn ); - return VCDINFO_INVALID_LID; - } - - if (offset != VCDINFO_INVALID_OFFSET) { - vcdinfo_offset_t *ofs; - int old = entry_num; - - switch (offset) { - case PSD_OFS_DISABLED: - LOG_ERR( "Selection %u disabled", entry_num ); - return VCDINFO_INVALID_LID; - case PSD_OFS_MULTI_DEF: - LOG_ERR( "Selection %u multi_def", entry_num ); - return VCDINFO_INVALID_LID; - case PSD_OFS_MULTI_DEF_NO_NUM: - LOG_ERR( "Selection %u multi_def_no_num", entry_num ); - return VCDINFO_INVALID_LID; - default: ; - } - - ofs = vcdinfo_get_offset_t(obj, offset); + vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; - if (NULL == ofs) { - LOG_ERR( "error in vcdinfo_get_offset" ); - return -1; - } - dbg_print(INPUT_DBG_PBC, - "entry %u turned into selection lid %u", - old, ofs->lid); - return ofs->lid; - - } else { - LOG_ERR( "invalid or unset entry %u", entry_num ); - return VCDINFO_INVALID_LID; + switch (itemid.type) { + case VCDINFO_ITEM_TYPE_ENTRY: + return p_vcdplayer->entry[itemid.num].size; + break; + case VCDINFO_ITEM_TYPE_SEGMENT: + return p_vcdplayer->segment[itemid.num].size; + break; + case VCDINFO_ITEM_TYPE_TRACK: + return p_vcdplayer->track[itemid.num-1].size; + break; + case VCDINFO_ITEM_TYPE_LID: + /* Play list number (LID) */ + return 0; + break; + case VCDINFO_ITEM_TYPE_NOTFOUND: + case VCDINFO_ITEM_TYPE_SPAREID2: + default: + LOG_ERR("%s %d", "bad item type", itemid.type); + return 0; } } -static void -vcdplayer_update_entry( input_thread_t * p_input, uint16_t ofs, +static void +vcdplayer_update_entry( access_t * p_access, uint16_t ofs, uint16_t *entry, const char *label) { - thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data; + vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; if ( ofs == VCDINFO_INVALID_OFFSET ) { *entry = VCDINFO_INVALID_ENTRY; } else { - vcdinfo_offset_t *off_t = vcdinfo_get_offset_t(p_vcd->vcd, ofs); - if (off_t != NULL) { - *entry = off_t->lid; - dbg_print(INPUT_DBG_PBC, "%s: %d\n", label, off_t->lid); + vcdinfo_offset_t *off = vcdinfo_get_offset_t(p_vcdplayer->vcd, ofs); + if (off != NULL) { + *entry = off->lid; + dbg_print(INPUT_DBG_PBC, "%s: LID %d", label, off->lid); } else *entry = VCDINFO_INVALID_ENTRY; } @@ -130,41 +109,29 @@ vcdplayer_update_entry( input_thread_t * p_input, uint16_t ofs, return true if the caller should return. */ -vcdplayer_read_status_t -vcdplayer_non_pbc_nav ( input_thread_t * p_input ) +vcdplayer_read_status_t +vcdplayer_non_pbc_nav ( access_t *p_access, uint8_t *wait_time ) { - thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data; + vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; /* Not in playback control. Do we advance automatically or stop? */ - switch (p_vcd->play_item.type) { + switch (p_vcdplayer->play_item.type) { case VCDINFO_ITEM_TYPE_TRACK: case VCDINFO_ITEM_TYPE_ENTRY: { - input_area_t *p_area; - - dbg_print( INPUT_DBG_LSN, "new track %d, lsn %d", p_vcd->cur_track, - p_vcd->p_sectors[p_vcd->cur_track+1] ); - - if ( p_vcd->cur_track >= p_vcd->num_tracks - 1 ) - return READ_END; /* EOF */ - - p_vcd->play_item.num = p_vcd->cur_track++; - - vlc_mutex_lock( &p_input->stream.stream_lock ); - p_area = p_input->stream.pp_areas[p_vcd->cur_track]; - - p_area->i_part = 1; - VCDSetArea( p_input, p_area ); - vlc_mutex_unlock( &p_input->stream.stream_lock ); - return READ_BLOCK; + if ( ! vcdplayer_play_next( p_access ) ) + { + return READ_END; + } break; } case VCDINFO_ITEM_TYPE_SPAREID2: dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN), "SPAREID2" ); - /* FIXME */ - p_input->stream.b_seekable = 0; - if (p_vcd->in_still) + if (p_vcdplayer->in_still) { + dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN), + "End of still spareid2" ); + *wait_time = 255; return READ_STILL_FRAME ; } return READ_END; @@ -177,11 +144,11 @@ vcdplayer_non_pbc_nav ( input_thread_t * p_input ) case VCDINFO_ITEM_TYPE_SEGMENT: /* Hack: Just go back and do still again */ /* FIXME */ - p_input->stream.b_seekable = 0; - if (p_vcd->in_still) + if (p_vcdplayer->in_still) { dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN), - "End of Segment - looping" ); + "End of still Segment" ); + *wait_time = 10; return READ_STILL_FRAME; } return READ_END; @@ -189,91 +156,367 @@ vcdplayer_non_pbc_nav ( input_thread_t * p_input ) return READ_BLOCK; } -/* FIXME: Will do whatever the right thing is later. */ -#define SLEEP_1_SEC_AND_HANDLE_EVENTS sleep(1) +/*! + 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: + ; + } + } +} /* Handles PBC navigation when reaching the end of a play item. */ vcdplayer_read_status_t -vcdplayer_pbc_nav ( input_thread_t * p_input ) +vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time ) { - thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data; + vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; /* We are in playback control. */ vcdinfo_itemid_t itemid; - if (0 != p_vcd->in_still && p_vcd->in_still != -5) { - SLEEP_1_SEC_AND_HANDLE_EVENTS; - if (p_vcd->in_still > 0) p_vcd->in_still--; - return READ_STILL_FRAME; - } - /* The end of an entry is really the end of the associated sequence (or track). */ - if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type) && - (p_vcd->cur_lsn < p_vcd->end_lsn) ) { + if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) && + (p_vcdplayer->i_lsn < p_vcdplayer->end_lsn) ) { /* Set up to just continue to the next entry */ - p_vcd->play_item.num++; + p_vcdplayer->play_item.num++; dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), - "continuing into next entry: %u", p_vcd->play_item.num); - VCDPlay( p_input, p_vcd->play_item ); - /* p_vcd->update_title(); */ + "continuing into next entry: %u", p_vcdplayer->play_item.num); + vcdplayer_play_single_item( p_access, p_vcdplayer->play_item ); + /* p_vcdplayer->update_title(); */ return READ_BLOCK; } - switch (p_vcd->pxd.descriptor_type) { + switch (p_vcdplayer->pxd.descriptor_type) { case PSD_TYPE_END_LIST: return READ_END; break; case PSD_TYPE_PLAY_LIST: { - int wait_time = vcdinf_get_wait_time(p_vcd->pxd.pld); - - dbg_print(INPUT_DBG_PBC, "playlist wait_time: %d", wait_time); - - if (vcdplayer_inc_play_item(p_input)) + if (vcdplayer_inc_play_item(p_access)) return READ_BLOCK; - /* Handle any wait time given. */ - if (-5 == p_vcd->in_still) { - if (wait_time != 0) { - /* FIXME */ - p_vcd->in_still = wait_time - 1; - SLEEP_1_SEC_AND_HANDLE_EVENTS ; - return READ_STILL_FRAME; - } + /* Set up for caller process wait time given. */ + if (p_vcdplayer->i_still) { + *wait_time = vcdinf_get_wait_time(p_vcdplayer->pxd.pld); + dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL), + "playlist wait time: %d", *wait_time); + return READ_STILL_FRAME; } - vcdplayer_update_entry( p_input, - vcdinf_pld_get_next_offset(p_vcd->pxd.pld), + + /* Wait time has been processed; continue with next entry. */ + vcdplayer_update_entry( p_access, + vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld), &itemid.num, "next" ); itemid.type = VCDINFO_ITEM_TYPE_LID; - VCDPlay( p_input, itemid ); + vcdplayer_play( p_access, itemid ); break; } case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */ case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */ { - int wait_time = vcdinf_get_timeout_time(p_vcd->pxd.psd); - uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcd->pxd.psd); - uint16_t max_loop = vcdinf_get_loop_count(p_vcd->pxd.psd); + uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcdplayer->pxd.psd); + uint16_t max_loop = vcdinf_get_loop_count(p_vcdplayer->pxd.psd); vcdinfo_offset_t *offset_timeout_LID = - vcdinfo_get_offset_t(p_vcd->vcd, timeout_offs); + vcdinfo_get_offset_t(p_vcdplayer->vcd, timeout_offs); - dbg_print(INPUT_DBG_PBC, "wait_time: %d, looped: %d, max_loop %d", - wait_time, p_vcd->loop_count, max_loop); + dbg_print(INPUT_DBG_PBC, "looped: %d, max_loop %d", + p_vcdplayer->i_loop, max_loop); - /* Handle any wait time given */ - if (-5 == p_vcd->in_still) { - p_vcd->in_still = wait_time - 1; - SLEEP_1_SEC_AND_HANDLE_EVENTS ; - return READ_STILL_FRAME; - } + /* Set up for caller process wait time given. */ + if (p_vcdplayer->i_still) { + *wait_time = vcdinf_get_timeout_time(p_vcdplayer->pxd.psd); + dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL), + "playlist wait_time: %d", *wait_time); + return READ_STILL_FRAME; + } + /* Wait time has been processed; continue with next entry. */ /* Handle any looping given. */ - if ( max_loop == 0 || p_vcd->loop_count < max_loop ) { - p_vcd->loop_count++; - if (p_vcd->loop_count == 0x7f) p_vcd->loop_count = 0; - VCDSeek( p_input, 0 ); - /* if (p_vcd->in_still) p_vcd->force_redisplay();*/ + if ( max_loop == 0 || p_vcdplayer->i_loop < max_loop ) { + p_vcdplayer->i_loop++; + if (p_vcdplayer->i_loop == 0x7f) p_vcdplayer->i_loop = 0; + vcdplayer_play_single_item(p_access, p_vcdplayer->loop_item); + /* if (p_vcdplayer->i_still) p_vcdplayer->force_redisplay();*/ return READ_BLOCK; } @@ -285,25 +528,27 @@ vcdplayer_pbc_nav ( input_thread_t * p_input ) itemid.num = offset_timeout_LID->lid; itemid.type = VCDINFO_ITEM_TYPE_LID; dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num); - VCDPlay( p_input, itemid ); + vcdplayer_play( p_access, itemid ); return READ_BLOCK; } else { - int num_selections = vcdinf_get_num_selections(p_vcd->pxd.psd); - if (num_selections > 0) { + int i_selections = vcdinf_get_num_selections(p_vcdplayer->pxd.psd); + if (i_selections > 0) { /* Pick a random selection. */ - unsigned int bsn=vcdinf_get_bsn(p_vcd->pxd.psd); + unsigned int bsn=vcdinf_get_bsn(p_vcdplayer->pxd.psd); int rand_selection=bsn + - (int) ((num_selections+0.0)*rand()/(RAND_MAX+1.0)); - lid_t rand_lid=vcdplayer_selection2lid (p_input, rand_selection); + (int) ((i_selections+0.0)*rand()/(RAND_MAX+1.0)); + lid_t rand_lid=vcdinfo_selection_get_lid (p_vcdplayer->vcd, + p_vcdplayer->i_lid, + rand_selection); itemid.num = rand_lid; itemid.type = VCDINFO_ITEM_TYPE_LID; dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d", rand_selection - bsn, rand_lid); - VCDPlay( p_input, itemid ); + vcdplayer_play( p_access, itemid ); return READ_BLOCK; - } else if (p_vcd->in_still) { + } else if (p_vcdplayer->i_still) { /* Hack: Just go back and do still again */ - SLEEP_1_SEC_AND_HANDLE_EVENTS ; + msleep(1000); return READ_STILL_FRAME; } } @@ -327,43 +572,396 @@ vcdplayer_pbc_nav ( input_thread_t * p_input ) return READ_ERROR; } -/* - 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. - */ -bool -vcdplayer_inc_play_item( input_thread_t *p_input ) +/*! + Read block into p_buf and return the status back. + + This routine is a bit complicated because on reaching the end of + a track or entry we may automatically advance to the item, or + interpret the next item in the playback-control list. +*/ +vcdplayer_read_status_t +vcdplayer_read (access_t * p_access, uint8_t *p_buf) { - thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data; - int noi; + /* p_access->handle_events (); */ + uint8_t wait_time; + + vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; + if ( p_vcdplayer->i_lsn > p_vcdplayer->end_lsn ) { + vcdplayer_read_status_t read_status; + + /* We've run off of the end of this entry. Do we continue or stop? */ + dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), + "end reached, cur: %u, end: %u\n", p_vcdplayer->i_lsn, p_vcdplayer->end_lsn); + + handle_item_continuation: + read_status = vcdplayer_pbc_is_on( p_vcdplayer ) + ? vcdplayer_pbc_nav( p_access, &wait_time ) + : vcdplayer_non_pbc_nav( p_access, &wait_time ); + + if (READ_STILL_FRAME == read_status) { + *p_buf = wait_time; + return READ_STILL_FRAME; + } + + if (READ_BLOCK != read_status) return read_status; + } - dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcd->pdi); + /* Read the next block. + + Important note: we probably speed things up by removing "data" + and the memcpy to it by extending vcd_image_source_read_mode2 + to allow a mode to do what's below in addition to its + "raw" and "block" mode. It also would probably improve the modularity + a little bit as well. + */ + + { + CdIo *p_img = vcdinfo_get_cd_image(p_vcdplayer->vcd); + typedef struct { + uint8_t subheader [CDIO_CD_SUBHEADER_SIZE]; + uint8_t data [M2F2_SECTOR_SIZE]; + uint8_t spare [4]; + } vcdsector_t; + vcdsector_t vcd_sector; + + do { + if (cdio_read_mode2_sector(p_img, &vcd_sector, + p_vcdplayer->i_lsn, true)!=0) { + dbg_print(INPUT_DBG_LSN, "read error\n"); + p_vcdplayer->i_lsn++; + return READ_ERROR; + } + p_vcdplayer->i_lsn++; + + if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) { + /* We've run off of the end of this entry. Do we continue or stop? */ + dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), + "end reached in reading, cur: %u, end: %u\n", + p_vcdplayer->i_lsn, p_vcdplayer->end_lsn); + break; + } + + /* Check header ID for a padding sector and simply discard + these. It is alleged that VCD's put these in to keep the + bitrate constant. + */ + } while((vcd_sector.subheader[2]&~0x01)==0x60); + + if ( p_vcdplayer->i_lsn >= p_vcdplayer->end_lsn ) + /* We've run off of the end of this entry. Do we continue or stop? */ + goto handle_item_continuation; + + memcpy (p_buf, vcd_sector.data, M2F2_SECTOR_SIZE); + return READ_BLOCK; + } +} + +/*! + Play item assocated with the "default" selection. + + Return false if there was some problem. +*/ +bool +vcdplayer_play_default( access_t * p_access ) +{ + vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; - if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return false; + vcdinfo_itemid_t itemid; - noi = vcdinf_pld_get_noi(p_vcd->pxd.pld); + if (!p_vcdplayer) { + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), + "null p_vcdplayer" ); + return VLC_EGENERIC; + } - if ( noi <= 0 ) return false; + + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), + "current: %d" , p_vcdplayer->play_item.num); + + itemid.type = p_vcdplayer->play_item.type; + + if (vcdplayer_pbc_is_on(p_vcdplayer)) { + +#if defined(LIBVCD_VERSION) + lid_t lid=vcdinfo_get_multi_default_lid(p_vcdplayer->vcd, p_vcdplayer->i_lid, + p_vcdplayer->i_lsn); + + if (VCDINFO_INVALID_LID != lid) { + itemid.num = lid; + itemid.type = VCDINFO_ITEM_TYPE_LID; + dbg_print(INPUT_DBG_PBC, "DEFAULT to %d", itemid.num); + } else { + dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d", p_vcdplayer->i_lid); + return VLC_EGENERIC; + } + +#else + vcdinfo_lid_get_pxd(p_vcdplayer->vcd, &(p_vcdplayer->pxd), p_vcdplayer->i_lid); + + switch (p_vcdplayer->pxd.descriptor_type) { + case PSD_TYPE_SELECTION_LIST: + case PSD_TYPE_EXT_SELECTION_LIST: + if (p_vcdplayer->pxd.psd == NULL) return false; + vcdplayer_update_entry( p_access, + vcdinfo_get_default_offset(p_vcdplayer->vcd, + p_vcdplayer->i_lid), + &itemid.num, "default"); + break; + + case PSD_TYPE_PLAY_LIST: + case PSD_TYPE_END_LIST: + case PSD_TYPE_COMMAND_LIST: + LOG_WARN( "There is no PBC 'default' selection here" ); + return false; + } +#endif /* LIBVCD_VERSION (< 0.7.21) */ + + + } else { + + /* PBC is not on. "default" selection beginning of current + selection . */ - /* Handle delays like autowait or wait here? */ + itemid.num = p_vcdplayer->play_item.num; + + } - p_vcd->pdi++; + /** ??? p_vcdplayer->update_title(); ***/ + vcdplayer_play( p_access, itemid ); + return VLC_SUCCESS; - if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return false; +} - else { - uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld, - p_vcd->pdi); - vcdinfo_itemid_t trans_itemid; +/*! + Play item assocated with the "next" selection. - if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false; + Return false if there was some problem. +*/ +bool +vcdplayer_play_next( access_t * p_access ) +{ + vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; + + vcdinfo_obj_t *p_vcdinfo; + vcdinfo_itemid_t itemid; + + if (!p_vcdplayer) return false; + + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), + "current: %d" , p_vcdplayer->play_item.num); + + p_vcdinfo = p_vcdplayer->vcd; + + itemid = p_vcdplayer->play_item; + + if (vcdplayer_pbc_is_on(p_vcdplayer)) { + + vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid); - vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid); - dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s", - p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num)); - return VLC_SUCCESS == VCDPlay( p_input, trans_itemid ); + switch (p_vcdplayer->pxd.descriptor_type) { + case PSD_TYPE_SELECTION_LIST: + case PSD_TYPE_EXT_SELECTION_LIST: + if (p_vcdplayer->pxd.psd == NULL) return false; + vcdplayer_update_entry( p_access, + vcdinf_psd_get_next_offset(p_vcdplayer->pxd.psd), + &itemid.num, "next"); + itemid.type = VCDINFO_ITEM_TYPE_LID; + break; + + case PSD_TYPE_PLAY_LIST: + if (p_vcdplayer->pxd.pld == NULL) return false; + vcdplayer_update_entry( p_access, + vcdinf_pld_get_next_offset(p_vcdplayer->pxd.pld), + &itemid.num, "next"); + itemid.type = VCDINFO_ITEM_TYPE_LID; + break; + + case PSD_TYPE_END_LIST: + case PSD_TYPE_COMMAND_LIST: + LOG_WARN( "There is no PBC 'next' selection here" ); + return false; + } + } else { + + /* PBC is not on. "Next" selection is play_item.num+1 if possible. */ + + int max_entry = 0; + + switch (p_vcdplayer->play_item.type) { + case VCDINFO_ITEM_TYPE_ENTRY: + case VCDINFO_ITEM_TYPE_SEGMENT: + case VCDINFO_ITEM_TYPE_TRACK: + + switch (p_vcdplayer->play_item.type) { + case VCDINFO_ITEM_TYPE_ENTRY: + max_entry = p_vcdplayer->i_entries; + break; + case VCDINFO_ITEM_TYPE_SEGMENT: + max_entry = p_vcdplayer->i_segments; + break; + case VCDINFO_ITEM_TYPE_TRACK: + max_entry = p_vcdplayer->i_tracks; + break; + default: ; /* Handle exceptional cases below */ + } + + if (p_vcdplayer->play_item.num+1 < max_entry) { + itemid.num = p_vcdplayer->play_item.num+1; + } else { + LOG_WARN( "At the end - non-PBC 'next' not possible here" ); + return false; + } + + break; + + case VCDINFO_ITEM_TYPE_LID: + { + /* Should have handled above. */ + LOG_WARN( "Internal inconsistency - should not have gotten here." ); + return false; + } + default: + return false; + } } + + /** ??? p_vcdplayer->update_title(); ***/ + vcdplayer_play( p_access, itemid ); + return VLC_SUCCESS; + } + +/*! + Play item assocated with the "prev" selection. + + Return false if there was some problem. +*/ +bool +vcdplayer_play_prev( access_t * p_access ) +{ + vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; + vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd; + vcdinfo_itemid_t itemid; + + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), + "current: %d" , p_vcdplayer->play_item.num); + + itemid = p_vcdplayer->play_item; + + if (vcdplayer_pbc_is_on(p_vcdplayer)) { + + vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid); + + switch (p_vcdplayer->pxd.descriptor_type) { + case PSD_TYPE_SELECTION_LIST: + case PSD_TYPE_EXT_SELECTION_LIST: + if (p_vcdplayer->pxd.psd == NULL) return false; + vcdplayer_update_entry( p_access, + vcdinf_psd_get_prev_offset(p_vcdplayer->pxd.psd), + &itemid.num, "prev"); + itemid.type = VCDINFO_ITEM_TYPE_LID; + break; + + case PSD_TYPE_PLAY_LIST: + if (p_vcdplayer->pxd.pld == NULL) return false; + vcdplayer_update_entry( p_access, + vcdinf_pld_get_prev_offset(p_vcdplayer->pxd.pld), + &itemid.num, "prev"); + itemid.type = VCDINFO_ITEM_TYPE_LID; + break; + + case PSD_TYPE_END_LIST: + case PSD_TYPE_COMMAND_LIST: + LOG_WARN( "There is no PBC 'prev' selection here" ); + return false; + } + } else { + + /* PBC is not on. "Prev" selection is play_item.num-1 if possible. */ + + int min_entry = (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) + ? 0 : 1; + + if (p_vcdplayer->play_item.num > min_entry) { + itemid.num = p_vcdplayer->play_item.num-1; + } else { + LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" ); + return false; + } + + } + + /** ??? p_vcdplayer->update_title(); ***/ + vcdplayer_play( p_access, itemid ); + return VLC_SUCCESS; + +} + +/*! + Play item assocated with the "return" selection. + + Return false if there was some problem. +*/ +bool +vcdplayer_play_return( access_t * p_access ) +{ + vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; + vcdinfo_obj_t *p_vcdinfo = p_vcdplayer->vcd; + vcdinfo_itemid_t itemid; + + dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), + "current: %d" , p_vcdplayer->play_item.num); + + itemid = p_vcdplayer->play_item; + + if (vcdplayer_pbc_is_on(p_vcdplayer)) { + + vcdinfo_lid_get_pxd(p_vcdinfo, &(p_vcdplayer->pxd), p_vcdplayer->i_lid); + + switch (p_vcdplayer->pxd.descriptor_type) { + case PSD_TYPE_SELECTION_LIST: + case PSD_TYPE_EXT_SELECTION_LIST: + if (p_vcdplayer->pxd.psd == NULL) return false; + vcdplayer_update_entry( p_access, + vcdinf_psd_get_return_offset(p_vcdplayer->pxd.psd), + &itemid.num, "return"); + itemid.type = VCDINFO_ITEM_TYPE_LID; + break; + + case PSD_TYPE_PLAY_LIST: + if (p_vcdplayer->pxd.pld == NULL) return false; + vcdplayer_update_entry( p_access, + vcdinf_pld_get_return_offset(p_vcdplayer->pxd.pld), + &itemid.num, "return"); + itemid.type = VCDINFO_ITEM_TYPE_LID; + break; + + case PSD_TYPE_END_LIST: + case PSD_TYPE_COMMAND_LIST: + LOG_WARN( "There is no PBC 'return' selection here" ); + return false; + } + } else { + + /* PBC is not on. "Return" selection is min_entry if possible. */ + + p_vcdplayer->play_item.num = + (VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type) + ? 0 : 1; + + } + + /** ??? p_vcdplayer->update_title(); ***/ + vcdplayer_play( p_access, itemid ); + return VLC_SUCCESS; + +} + +/* + * Local variables: + * c-file-style: "gnu" + * tab-width: 8 + * indent-tabs-mode: nil + * End: + */