📄 access.c
字号:
/***************************************************************************** * vcd.c : VCD input module for vlc using libcdio, libvcd and libvcdinfo. * vlc-specific things tend to go here. ***************************************************************************** * Copyright (C) 2000, 2003, 2004, 2005 VideoLAN * $Id: access.c 10862 2005-05-01 14:48:08Z rocky $ * * Authors: Rocky Bernstein <rocky@panix.com> * Some code is based on the non-libcdio VCD plugin (as there really * isn't real developer documentation yet on how to write a * navigable plugin.) * * 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/intf.h>#include <vlc/input.h>#include "vlc_keys.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 "vcd.h"#include "info.h"#include "intf.h"#define FREE_AND_NULL(ptr) free(ptr); ptr = NULL;extern void VCDSetOrigin( access_t *p_access, lsn_t i_lsn, track_t i_track, const vcdinfo_itemid_t *p_itemid );/***************************************************************************** * Local prototypes *****************************************************************************//* First those which are accessed from outside (via pointers). */static block_t *VCDReadBlock ( access_t * );static int VCDControl ( access_t *p_access, int i_query, va_list args );/* Now those which are strictly internal */static vlc_bool_t VCDEntryPoints ( access_t * );static vlc_bool_t VCDLIDs ( access_t * );static vlc_bool_t VCDSegments ( access_t * );static int VCDTitles ( access_t * );static char *VCDParse ( access_t *, /*out*/ vcdinfo_itemid_t * p_itemid , /*out*/ vlc_bool_t *play_single_item );static void VCDUpdateVar( access_t *p_access, 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 access_t *p_vcd_access = NULL;/* process messages that originate from libcdio. */static voidcdio_log_handler (cdio_log_level_t level, const char message[]){ const vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys; switch (level) { case CDIO_LOG_DEBUG: case CDIO_LOG_INFO: if (p_vcdplayer->i_debug & INPUT_DBG_CDIO) msg_Dbg( p_vcd_access, message); break; case CDIO_LOG_WARN: msg_Warn( p_vcd_access, message); break; case CDIO_LOG_ERROR: case CDIO_LOG_ASSERT: msg_Err( p_vcd_access, message); break; default: msg_Warn( p_vcd_access, 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[]){ vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys; switch (level) { case VCD_LOG_DEBUG: case VCD_LOG_INFO: if (p_vcdplayer->i_debug & INPUT_DBG_VCDINFO) msg_Dbg( p_vcd_access, message); break; case VCD_LOG_WARN: msg_Warn( p_vcd_access, message); break; case VCD_LOG_ERROR: case VCD_LOG_ASSERT: msg_Err( p_vcd_access, message); break; default: msg_Warn( p_vcd_access, "%s\n%s %d", message, _("The above message had unknown vcdimager log level"), level); } return;}/***************************************************************************** VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that. NULL is returned if something went wrong. *****************************************************************************/static block_t *VCDReadBlock( access_t * p_access ){ vcdplayer_t *p_vcdplayer= (vcdplayer_t *)p_access->p_sys; const int i_blocks = p_vcdplayer->i_blocks_per_read; block_t *p_block; int i_read; uint8_t *p_buf; i_read = 0; dbg_print( (INPUT_DBG_LSN), "lsn: %lu", (long unsigned int) p_vcdplayer->i_lsn ); /* Allocate a block for the reading */ if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) ) { msg_Err( p_access, "cannot get a new block of size: %i", i_blocks * M2F2_SECTOR_SIZE ); block_Release( p_block ); return NULL; } p_buf = (uint8_t *) p_block->p_buffer; for ( i_read = 0 ; i_read < i_blocks ; i_read++ ) { vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf); p_access->info.i_pos += M2F2_SECTOR_SIZE; switch ( read_status ) { case READ_END: /* End reached. Return NULL to indicated this. */ /* We also set the postion to the end so the higher level (demux?) doesn't try to keep reading. If everything works out right this shouldn't have to happen. */#if 0 if ( p_access->info.i_pos != p_access->info.i_size ) { msg_Warn( p_access, "At end but pos (%llu) is not size (%llu). Adjusting.", p_access->info.i_pos, p_access->info.i_size ); p_access->info.i_pos = p_access->info.i_size; }#endif block_Release( p_block ); return NULL; case READ_ERROR: /* Some sort of error. Should we increment lsn? to skip block? */ block_Release( p_block ); return NULL; case READ_STILL_FRAME: { /* FIXME The below should be done in an event thread. Until then... */#if 1 msleep( MILLISECONDS_PER_SEC * *p_buf ); VCDSetOrigin(p_access, p_vcdplayer->origin_lsn, p_vcdplayer->i_track, &(p_vcdplayer->play_item)); // p_vcd->in_still = VLC_FALSE; dbg_print(INPUT_DBG_STILL, "still wait time done");#else vcdIntfStillTime(p_vcdplayer->p_intf, *p_buf);#endif block_Release( p_block ); return NULL; } default: case READ_BLOCK: /* Read buffer */ ; } p_buf += M2F2_SECTOR_SIZE; /* Update seekpoint */ if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcdplayer->play_item.type ) { unsigned int i_entry = p_vcdplayer->play_item.num+1; lsn_t i_lsn = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i_entry); if ( p_vcdplayer->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LSN ) { const track_t i_track = p_vcdplayer->i_track; dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC), "entry change to %d, current LSN %u >= end %u", i_entry, p_vcdplayer->i_lsn, i_lsn); p_vcdplayer->play_item.num = i_entry; VCDSetOrigin( p_access, i_lsn, i_track, &(p_vcdplayer->play_item) ); } } } return p_block;}/**************************************************************************** * VCDSeek ****************************************************************************/intVCDSeek( access_t * p_access, int64_t i_pos ){ if (!p_access || !p_access->p_sys) return VLC_EGENERIC; { vcdplayer_t *p_vcdplayer = (vcdplayer_t *)p_vcd_access->p_sys; const input_title_t *t = p_vcdplayer->p_title[p_access->info.i_title]; unsigned int i_entry = VCDINFO_INVALID_ENTRY; int i_seekpoint; /* Next sector to read */ p_access->info.i_pos = i_pos; p_vcdplayer->i_lsn = (i_pos / (int64_t) M2F2_SECTOR_SIZE) + p_vcdplayer->origin_lsn; switch (p_vcdplayer->play_item.type) { case VCDINFO_ITEM_TYPE_TRACK: case VCDINFO_ITEM_TYPE_ENTRY: break ; default: p_vcdplayer->b_valid_ep = VLC_FALSE; } /* Find entry */ if( p_vcdplayer->b_valid_ep ) { for( i_entry = 0 ; i_entry < p_vcdplayer->i_entries ; i_entry ++ ) { if( p_vcdplayer->i_lsn < p_vcdplayer->p_entries[i_entry] ) { VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE, "chapter", _("Entry"), "Setting entry" ); break; } } { vcdinfo_itemid_t itemid; itemid.num = i_entry; itemid.type = VCDINFO_ITEM_TYPE_ENTRY; VCDSetOrigin(p_access, p_vcdplayer->i_lsn, p_vcdplayer->i_track, &itemid); } } dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK), "orig %lu, cur: %lu, offset: %lld, entry %d", (long unsigned int) p_vcdplayer->origin_lsn, (long unsigned int) p_vcdplayer->i_lsn, i_pos, i_entry ); /* Find seekpoint */ for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ ) { if( i_seekpoint + 1 >= t->i_seekpoint ) break; if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break; } /* Update current seekpoint */ if( i_seekpoint != p_access->info.i_seekpoint ) { dbg_print( (INPUT_DBG_SEEK), "seekpoint change %lu", (long unsigned int) i_seekpoint ); p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT; p_access->info.i_seekpoint = i_seekpoint; } } return VLC_SUCCESS; }/***************************************************************************** VCDEntryPoints: Reads the information about the entry points on the disc and initializes area information with that. Before calling this track information should have been read in. *****************************************************************************/static vlc_bool_tVCDEntryPoints( access_t * p_access ){ if (!p_access || !p_access->p_sys) return VLC_FALSE; { vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys; const unsigned int i_entries = vcdinfo_get_num_entries(p_vcdplayer->vcd); const track_t i_last_track = cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcdplayer->vcd)) + cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcdplayer->vcd)); unsigned int i; if (0 == i_entries) { LOG_ERR ("no entires found -- something is wrong" ); return VLC_FALSE; } p_vcdplayer->p_entries = malloc( sizeof( lsn_t ) * i_entries ); if( p_vcdplayer->p_entries == NULL ) { LOG_ERR ("not enough memory for entry points treatment" ); return VLC_FALSE; } p_vcdplayer->i_entries = i_entries; for( i = 0 ; i < i_entries ; i++ ) { const track_t i_track = vcdinfo_get_track(p_vcdplayer->vcd, i); if( i_track <= i_last_track ) { seekpoint_t *s = vlc_seekpoint_New(); char psz_entry[100]; snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i ); p_vcdplayer->p_entries[i] = vcdinfo_get_entry_lsn(p_vcdplayer->vcd, i); s->psz_name = strdup(psz_entry); s->i_byte_offset = (p_vcdplayer->p_entries[i] - vcdinfo_get_track_lsn(p_vcdplayer->vcd, i_track)) * M2F2_SECTOR_SIZE; dbg_print( INPUT_DBG_MRL, "%s, lsn %d, byte_offset %ld", s->psz_name, p_vcdplayer->p_entries[i], (unsigned long int) s->i_byte_offset); TAB_APPEND( p_vcdplayer->p_title[i_track-1]->i_seekpoint, p_vcdplayer->p_title[i_track-1]->seekpoint, s ); } else msg_Warn( p_access, "wrong track number found in entry points" ); } p_vcdplayer->b_valid_ep = VLC_TRUE; return VLC_TRUE; }}/***************************************************************************** * VCDSegments: Reads the information about the segments the disc. *****************************************************************************/static vlc_bool_tVCDSegments( access_t * p_access ){ vcdplayer_t *p_vcdplayer = (vcdplayer_t *) p_access->p_sys; unsigned int i; input_title_t *t; p_vcdplayer->i_segments = vcdinfo_get_num_segments(p_vcdplayer->vcd); dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL), "Segments: %d", p_vcdplayer->i_segments); if ( 0 == p_vcdplayer->i_segments ) return VLC_FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -