access.c
来自「VLC媒体播放程序」· C语言 代码 · 共 1,611 行 · 第 1/4 页
C
1,611 行
/***************************************************************************** * vcd.c : VCD input module for vlc * using libcdio, libvcd and libvcdinfo. vlc-specific things tend * to go here. ***************************************************************************** * Copyright (C) 2000, 2003, 2004 VideoLAN * $Id: access.c,v 1.21 2004/02/22 10:30:41 rocky Exp $ * * Authors: Rocky Bernstein <rocky@panix.com> * Johan Bilien <jobi@via.ecp.fr> * * 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. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <vlc/vlc.h>#include <vlc/input.h>#include <vlc/intf.h>#include "../../demux/mpeg/system.h"#include "vcd.h"#include "vcdplayer.h"#include "intf.h"#include <cdio/cdio.h>#include <cdio/cd_types.h>#include <cdio/logging.h>#include <cdio/util.h>#include <libvcd/info.h>#include <libvcd/logging.h>#include "cdrom.h"/* how many blocks VCDRead will read in each loop */#define VCD_BLOCKS_ONCE 20#define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE)#define VCD_MRL_PREFIX "vcdx://"/***************************************************************************** * Local prototypes *****************************************************************************//* First those which are accessed from outside (via pointers). */static int VCDRead ( input_thread_t *, byte_t *, size_t );static int VCDSetProgram ( input_thread_t *, pgrm_descriptor_t * );/* Now those which are strictly internal */static void VCDSetOrigin ( input_thread_t *, lsn_t origin_lsn, lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t track );static int VCDEntryPoints ( input_thread_t * );static int VCDLIDs ( input_thread_t * );static int VCDSegments ( input_thread_t * );static void VCDTracks ( input_thread_t * );static int VCDReadSector ( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn, byte_t * p_buffer );static char *VCDParse ( input_thread_t *, /*out*/ vcdinfo_itemid_t * p_itemid , /*out*/ bool *play_single_item );static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action, const char *p_varname, char *p_label, const char *p_debug_label );static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );/**************************************************************************** * Private functions ****************************************************************************//* FIXME: This variable is a hack. Would be nice to eliminate the global-ness. */static input_thread_t *p_vcd_input = NULL;/* process messages that originate from libcdio. */static voidcdio_log_handler (cdio_log_level_t level, const char message[]){ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data; switch (level) { case CDIO_LOG_DEBUG: case CDIO_LOG_INFO: if (p_vcd->i_debug & INPUT_DBG_CDIO) msg_Dbg( p_vcd_input, message); break; case CDIO_LOG_WARN: msg_Warn( p_vcd_input, message); break; case CDIO_LOG_ERROR: case CDIO_LOG_ASSERT: msg_Err( p_vcd_input, message); break; default: msg_Warn( p_vcd_input, message, _("The above message had unknown log level"), level); } return;}/* process messages that originate from vcdinfo. */static voidvcd_log_handler (vcd_log_level_t level, const char message[]){ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data; switch (level) { case VCD_LOG_DEBUG: case VCD_LOG_INFO: if (p_vcd->i_debug & INPUT_DBG_VCDINFO) msg_Dbg( p_vcd_input, message); break; case VCD_LOG_WARN: msg_Warn( p_vcd_input, message); break; case VCD_LOG_ERROR: case VCD_LOG_ASSERT: msg_Err( p_vcd_input, message); break; default: msg_Warn( p_vcd_input, "%s\n%s %d", message, _("The above message had unknown vcdimager log level"), level); } return;}/***************************************************************************** * VCDRead: reads i_len bytes from the VCD into p_buffer. ***************************************************************************** * Returns -1 in case of error, 0 in case of EOF, otherwise the number of * bytes. *****************************************************************************/static intVCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ){ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data; int i_blocks; int i_index; int i_read; byte_t p_last_sector[ M2F2_SECTOR_SIZE ]; i_read = 0; dbg_print( (INPUT_DBG_CALL), "lsn: %u", p_vcd->cur_lsn ); /* Compute the number of blocks we have to read */ i_blocks = i_len / M2F2_SECTOR_SIZE; for ( i_index = 0 ; i_index < i_blocks ; i_index++ ) { if ( p_vcd->cur_lsn == p_vcd->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", p_vcd->cur_lsn ); read_status = vcdplayer_pbc_is_on( p_vcd ) ? vcdplayer_pbc_nav( p_input ) : vcdplayer_non_pbc_nav( p_input ); switch (read_status) { case READ_END: /* End reached. Return NULL to indicated this. */ case READ_ERROR: /* Some sort of error. */ return i_read; case READ_STILL_FRAME: { /* Reached the end of a still frame. */ byte_t * p_buf = p_buffer; pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;; p_buf += (i_index*M2F2_SECTOR_SIZE); memset(p_buf, 0, M2F2_SECTOR_SIZE); p_buf += 2; *p_buf = 0x01; dbg_print(INPUT_DBG_STILL, "Handled still event");#if 1 p_vcd->p_intf->p_sys->b_still = 1; input_SetStatus( p_input, INPUT_STATUS_PAUSE );#endif vlc_mutex_lock( &p_input->stream.stream_lock ); p_pgrm = p_input->stream.p_selected_program; p_pgrm->i_synchro_state = SYNCHRO_REINIT; vlc_mutex_unlock( &p_input->stream.stream_lock ); input_ClockManageControl( p_input, p_pgrm, 0 ); p_vcd->p_intf->p_sys->b_still = 1; input_SetStatus( p_input, INPUT_STATUS_PAUSE ); return i_read + M2F2_SECTOR_SIZE; } default: case READ_BLOCK: break; } } if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd, p_vcd->cur_lsn, p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 ) { LOG_ERR ("could not read sector %d", p_vcd->cur_lsn ); return -1; } p_vcd->cur_lsn ++; /* Update chapter */ if( p_vcd->b_valid_ep && /* FIXME kludge so that read does not update chapter * when a manual chapter change was requested and not * yet accomplished */ !p_input->stream.p_new_area ) { unsigned int i_entry = p_input->stream.p_selected_area->i_part; vlc_mutex_lock( &p_input->stream.stream_lock ); if( i_entry < p_vcd->num_entries && p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] ) { dbg_print( INPUT_DBG_PBC, "new entry, i_entry %d, sector %d, es %d", i_entry, p_vcd->cur_lsn, p_vcd->p_entries[i_entry] ); p_vcd->play_item.num = ++ p_input->stream.p_selected_area->i_part; p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY; VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE, "chapter", _("Entry"), "Setting entry" ); } vlc_mutex_unlock( &p_input->stream.stream_lock ); } i_read += M2F2_SECTOR_SIZE; } if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */ { if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd, p_vcd->cur_lsn, p_last_sector ) < 0 ) { LOG_ERR ("could not read sector %d", p_vcd->cur_lsn ); return -1; } p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE, p_last_sector, i_len % M2F2_SECTOR_SIZE ); i_read += i_len % M2F2_SECTOR_SIZE; } return i_read;}/***************************************************************************** * VCDSetProgram: Does nothing since a VCD is mono_program *****************************************************************************/static intVCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program){ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data; dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" ); return 0;}/***************************************************************************** * VCDSetArea: initialize internal data structures and input stream data so set subsequent reading and seeking to reflect that we are at track x, entry or segment y. This is called for each user navigation request, e.g. the GUI Chapter/Title selections or in initial MRL parsing. ****************************************************************************/intVCDSetArea( input_thread_t * p_input, input_area_t * p_area ){ thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data; unsigned int i_entry = p_area->i_part; track_t i_track = p_area->i_id; int old_seekable = p_input->stream.b_seekable; unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb; dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "track: %d, entry %d, seekable %d, area %lx, select area %lx ", i_track, i_entry, old_seekable, (long unsigned int) p_area, (long unsigned int) p_input->stream.p_selected_area ); /* we can't use the interface slider until initilization is complete */ p_input->stream.b_seekable = 0; if( p_area != p_input->stream.p_selected_area ) { unsigned int i; /* If is the result of a track change, make the entry valid. */ if (i_entry < p_area->i_plugin_data || i_entry >= i_nb) i_entry = p_area->i_plugin_data; /* Change the default area */ p_input->stream.p_selected_area = p_area; /* Update the navigation variables without triggering a callback */ VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title", _("Track"), "Setting track"); var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL ); for( i = p_area->i_plugin_data; i < i_nb; i++ ) { VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE, "chapter", p_vcd->play_item.type == VCDINFO_ITEM_TYPE_SEGMENT ? _("Segment"): _("Entry"), "Adding entry choice"); } if (p_vcd->b_svd) { unsigned int audio_type = vcdinfo_get_track_audio_type(p_vcd->vcd, i_track); unsigned int i_channels = vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type); var_Change( p_input, "audio_channels", VLC_VAR_CLEARCHOICES, NULL, NULL ); for( i = 0; i < i_channels; i++ ) { VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE, "audio_channels", NULL, "Adding audio choice"); } } } if (i_track == 0) VCDSetOrigin( p_input, p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1], i_entry, 0 ); else VCDSetOrigin( p_input, p_vcd->p_sectors[i_track], vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry), p_vcd->p_sectors[i_track+1], i_entry, i_track ); p_input->stream.b_seekable = old_seekable; /* warn interface that something has changed */ p_input->stream.b_changed = 1; return VLC_SUCCESS;}/**************************************************************************** * VCDSeek ****************************************************************************/voidVCDSeek( input_thread_t * p_input, off_t i_off ){ thread_vcd_data_t * p_vcd; unsigned int i_entry=0; /* invalid entry */ p_vcd = (thread_vcd_data_t *) p_input->p_access_data; p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE); vlc_mutex_lock( &p_input->stream.stream_lock );#define p_area p_input->stream.p_selected_area /* Find entry */ if( p_vcd->b_valid_ep ) { for( i_entry = 0 ; i_entry < p_vcd->num_entries ; i_entry ++ ) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?