📄 vcdplayer.c
字号:
/***************************************************************************** * vcdplayer.c : VCD input module for vlc * using libcdio, libvcd and libvcdinfo ***************************************************************************** * Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com> * $Id: vcdplayer.c 10922 2005-05-07 20:02:48Z fkuehne $ * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//* This contains more of the vlc-independent parts that might be used in any VCD input module for a media player. However at present there are vlc-specific structures. See also vcdplayer.c of the xine plugin. *//***************************************************************************** * Preamble *****************************************************************************/#include <vlc/vlc.h>#include <vlc/input.h>#include <vlc/intf.h>#include "vcd.h"#include "vcdplayer.h"#include "intf.h"#include <string.h>#include <cdio/cdio.h>#include <cdio/util.h>#include <libvcd/info.h>#ifdef WIN32#define sleep(A) Sleep((A)*1000)#endifextern 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 vcdplayer_t *p_vcdplayer ) { return VCDINFO_INVALID_ENTRY != p_vcdplayer->i_lid; }/* Given an itemid, return the size for the object (via information previously stored when opening the vcd). */static size_tvcdplayer_get_item_size(access_t * p_access, vcdinfo_itemid_t itemid) { vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; 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( access_t * p_access, uint16_t ofs, uint16_t *entry, const char *label){ vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; if ( ofs == VCDINFO_INVALID_OFFSET ) { *entry = VCDINFO_INVALID_ENTRY; } else { 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; }}/* Handles navigation when NOT in PBC reaching the end of a play item. The navigations rules here may be sort of made up, but the intent is to do something that's probably right or helpful. return true if the caller should return.*/vcdplayer_read_status_t vcdplayer_non_pbc_nav ( access_t *p_access, uint8_t *wait_time ){ vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; /* Not in playback control. Do we advance automatically or stop? */ switch (p_vcdplayer->play_item.type) { case VCDINFO_ITEM_TYPE_TRACK: case VCDINFO_ITEM_TYPE_ENTRY: { if ( ! vcdplayer_play_next( p_access ) ) { return READ_END; } break; } case VCDINFO_ITEM_TYPE_SPAREID2: dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN), "SPAREID2" ); 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; case VCDINFO_ITEM_TYPE_NOTFOUND: LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen"); return READ_ERROR; case VCDINFO_ITEM_TYPE_LID: LOG_ERR ("LID outside PBC -- not supposed to happen"); return READ_ERROR; case VCDINFO_ITEM_TYPE_SEGMENT: /* Hack: Just go back and do still again */ /* FIXME */ if (p_vcdplayer->in_still) { dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN), "End of still Segment" ); *wait_time = 10; return READ_STILL_FRAME; } return READ_END; } return READ_BLOCK;}/*! 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 boolvcdplayer_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); 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 boolvcdplayer_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); }}voidvcdplayer_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_tvcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time ){ vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; /* We are in playback control. */ vcdinfo_itemid_t itemid; /* The end of an entry is really the end of the associated sequence (or track). */ 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_vcdplayer->play_item.num++; dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "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_vcdplayer->pxd.descriptor_type) { case PSD_TYPE_END_LIST: return READ_END; break; case PSD_TYPE_PLAY_LIST: { if (vcdplayer_inc_play_item(p_access)) return READ_BLOCK; /* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -