📄 access.c
字号:
/* access.c: DVD access plugin. ***************************************************************************** * This plugins should handle all the known specificities of the DVD format, * especially the 2048 bytes logical block size. * It depends on: * -libdvdcss for access and unscrambling * -ifo.* for ifo parsing and analyse * -udf.* to find files ***************************************************************************** * Copyright (C) 1998-2001 VideoLAN * $Id: access.c,v 1.15 2003/12/22 14:32:55 sam Exp $ * * Author: St閜hane Borel <stef@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 <stdio.h>#include <stdlib.h>#include <string.h>#include <vlc/vlc.h>#include <vlc/input.h>#include "../../demux/mpeg/system.h"#ifdef HAVE_UNISTD_H# include <unistd.h>#endif#include <fcntl.h>#include <sys/types.h>#include <sys/stat.h>#include <string.h>#include <errno.h>#ifdef STRNCASECMP_IN_STRINGS_H# include <strings.h>#endif#ifdef GOD_DAMN_DMCA# include "dvdcss.h"#else# include <dvdcss/dvdcss.h>#endif#include "dvd.h"#include "es.h"#include "seek.h"#include "ifo.h"#include "summary.h"#include "iso_lang.h"/***************************************************************************** * Local prototypes *****************************************************************************//* called from outside */static int DVDSetArea ( input_thread_t *, input_area_t * );static int DVDSetProgram ( input_thread_t *, pgrm_descriptor_t * );static ssize_t DVDRead ( input_thread_t *, byte_t *, size_t );static void DVDSeek ( input_thread_t *, off_t );static char * DVDParse( input_thread_t * );/* * Data access functions */#define DVDTell LB2OFF( p_dvd->i_vts_start + p_dvd->i_vts_lb ) \ - p_input->stream.p_selected_area->i_start/***************************************************************************** * DVDOpen: open dvd *****************************************************************************/int E_(DVDOpen) ( vlc_object_t *p_this ){ input_thread_t * p_input = (input_thread_t *)p_this; char * psz_device; thread_dvd_data_t * p_dvd; input_area_t * p_area; int i; char * psz_dvdcss_env; p_dvd = malloc( sizeof(thread_dvd_data_t) ); if( p_dvd == NULL ) { msg_Err( p_input, "out of memory" ); return -1; } p_input->p_access_data = (void *)p_dvd; p_input->pf_read = DVDRead; p_input->pf_seek = DVDSeek; p_input->pf_set_area = DVDSetArea; p_input->pf_set_program = DVDSetProgram; /* Parse command line */ if( !( psz_device = DVDParse( p_input ) ) ) { free( p_dvd ); return -1; } /* * set up input */ p_input->i_mtu = 0; /* override environment variable DVDCSS_METHOD with config option * (FIXME: this creates a small memory leak) */ psz_dvdcss_env = config_GetPsz( p_input, "dvdcss-method" ); if( psz_dvdcss_env && *psz_dvdcss_env ) { char *psz_env; psz_env = malloc( strlen("DVDCSS_METHOD=") + strlen( psz_dvdcss_env ) + 1 ); if( !psz_env ) { free( p_dvd ); return -1; } sprintf( psz_env, "%s%s", "DVDCSS_METHOD=", psz_dvdcss_env ); putenv( psz_env ); } if( psz_dvdcss_env ) free( psz_dvdcss_env ); /* * get plugin ready */ p_dvd->dvdhandle = dvdcss_open( psz_device ); /* free allocated string */ free( psz_device ); if( p_dvd->dvdhandle == NULL ) { msg_Err( p_input, "dvdcss cannot open device" ); free( p_dvd ); return -1; } if( dvdcss_seek( p_dvd->dvdhandle, 0, DVDCSS_NOFLAGS ) < 0 ) { msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) ); dvdcss_close( p_dvd->dvdhandle ); free( p_dvd ); return -1; } /* Ifo allocation & initialisation */ if( IfoCreate( p_dvd ) < 0 ) { msg_Err( p_input, "allcation error in ifo" ); dvdcss_close( p_dvd->dvdhandle ); free( p_dvd ); return -1; } if( IfoInit( p_dvd->p_ifo ) < 0 ) { msg_Err( p_input, "fatal failure in ifo" ); IfoDestroy( p_dvd->p_ifo ); dvdcss_close( p_dvd->dvdhandle ); free( p_dvd ); return -1; } /* Set stream and area data */ vlc_mutex_lock( &p_input->stream.stream_lock ); p_input->stream.i_method = INPUT_METHOD_DVD; p_input->stream.b_pace_control = 1; p_input->stream.b_seekable = 1; p_input->stream.p_selected_area->i_size = 0; p_input->stream.p_selected_area->i_tell = 0; /* Initialize ES structures */ input_InitStream( p_input, sizeof( stream_ps_data_t ) );#define title_inf p_dvd->p_ifo->vmg.title_inf msg_Dbg( p_input, "number of titles: %d", title_inf.i_title_nb );#define area p_input->stream.pp_areas /* We start from 1 here since the default area 0 * is reserved for video_ts.vob */ for( i = 1 ; i <= title_inf.i_title_nb ; i++ ) { /* Titles are Program Chains */ input_AddArea( p_input, i, title_inf.p_attr[i-1].i_chapter_nb ); /* Absolute start offset and size * We can only set that with vts ifo, so we do it during the * first call to DVDSetArea */ area[i]->i_start = 0; area[i]->i_size = 0; /* Default Chapter */ area[i]->i_part = 1; /* Offset to vts_i_0.ifo */ area[i]->i_plugin_data = p_dvd->p_ifo->i_start + title_inf.p_attr[i-1].i_start_sector; }#undef area p_dvd->i_title = p_dvd->i_title <= title_inf.i_title_nb ? p_dvd->i_title : 1;#undef title_inf p_area = p_input->stream.pp_areas[p_dvd->i_title]; p_area->i_part = p_dvd->i_chapter <= p_area->i_part_nb ? p_dvd->i_chapter : 1; p_dvd->i_chapter = 1; p_dvd->b_new_chapter = 0; p_dvd->i_audio_nb = 0; p_dvd->i_spu_nb = 0; /* set title, chapter, audio and subpic */ if( DVDSetArea( p_input, p_area ) < 0 ) { vlc_mutex_unlock( &p_input->stream.stream_lock ); IfoDestroy( p_dvd->p_ifo ); dvdcss_close( p_dvd->dvdhandle ); free( p_dvd ); return -1; } vlc_mutex_unlock( &p_input->stream.stream_lock ); if( !p_input->psz_demux || !*p_input->psz_demux ) { p_input->psz_demux = "dvdold"; } return 0;}/***************************************************************************** * DVDClose: close dvd *****************************************************************************/void E_(DVDClose) ( vlc_object_t *p_this ){ input_thread_t * p_input = (input_thread_t *)p_this; thread_dvd_data_t *p_dvd = (thread_dvd_data_t*)p_input->p_access_data; /* This is a very nasty side-effect in the DVD plug-in : language * selection here influences language selection of other streams. So * unset those variables (may not be what the user wants). * FIXME FIXME FIXME FIXME FIXME FIXME FIXME --Meuuh */ config_PutInt( p_input, "audio-channel", -1 ); config_PutInt( p_input, "spu-channel", -1 ); IfoDestroy( p_dvd->p_ifo ); dvdcss_close( p_dvd->dvdhandle ); free( p_dvd );}/***************************************************************************** * DVDSetProgram: used to change angle *****************************************************************************/static int DVDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program ){ if( p_input->stream.p_selected_program != p_program ) { thread_dvd_data_t * p_dvd; int i_angle; vlc_value_t val; p_dvd = (thread_dvd_data_t*)(p_input->p_access_data); i_angle = p_program->i_number; /* DVD is actually mono-program: we only need the current angle * number, so copy the data between programs */ memcpy( p_program, p_input->stream.p_selected_program, sizeof(pgrm_descriptor_t) ); p_program->i_number = i_angle; p_input->stream.p_selected_program = p_program;#define title \ p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 ) { if( ( p_program->i_number - p_dvd->i_angle ) < 0 ) { /* we have to go backwards */ p_dvd->i_map_cell = 0; } p_dvd->i_prg_cell += ( p_program->i_number - p_dvd->i_angle ); p_dvd->i_map_cell = CellPrg2Map( p_dvd ); p_dvd->i_map_cell += p_dvd->i_angle_cell; p_dvd->i_vts_lb = CellFirstSector( p_dvd ); p_dvd->i_last_lb = CellLastSector( p_dvd ); p_dvd->i_angle = p_program->i_number; } else { p_dvd->i_angle = p_program->i_number; }#undef title msg_Dbg( p_input, "angle %d selected", p_dvd->i_angle ); /* Update the navigation variables without triggering a callback */ val.i_int = p_program->i_number; var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL ); } return 0;}/***************************************************************************** * DVDSetArea: initialize input data for title x, chapter y. * It should be called for each user navigation request. ***************************************************************************** * Take care that i_title starts from 0 (vmg) and i_chapter start from 1. * Note that you have to take the lock before entering here. *****************************************************************************/#define vmg p_dvd->p_ifo->vmg#define vts p_dvd->p_ifo->vtsstatic void DVDFlushStream( input_thread_t * p_input ){ if( p_input->stream.pp_programs != NULL ) { /* We don't use input_EndStream here since * we keep area structures */ while( p_input->stream.i_es_number ) { input_DelES( p_input, p_input->stream.pp_es[0] ); } while( p_input->stream.i_pgrm_number ) { input_DelProgram( p_input, p_input->stream.pp_programs[0] ); } if( p_input->stream.pp_selected_es ) { free( p_input->stream.pp_selected_es ); p_input->stream.pp_selected_es = NULL; } p_input->stream.i_selected_es_number = 0; } return;}static int DVDReadAngle( input_thread_t * p_input ){ thread_dvd_data_t * p_dvd; int i_angle_nb; int i; p_dvd = (thread_dvd_data_t*)(p_input->p_access_data); i_angle_nb = vmg.title_inf.p_attr[p_dvd->i_title-1].i_angle_nb; input_AddProgram( p_input, 1, sizeof( stream_ps_data_t ) ); p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; for( i = 1 ; i < i_angle_nb ; i++ ) { input_AddProgram( p_input, i+1, 0 ); } return i_angle_nb;}static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area ){ thread_dvd_data_t * p_dvd; vlc_value_t val; p_dvd = (thread_dvd_data_t*)(p_input->p_access_data); /* 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 ) { int i_vts_title; uint32_t i_first; uint32_t i_last; unsigned int i; /* Reset the Chapter position of the old title */ p_input->stream.p_selected_area->i_part = 1; p_input->stream.p_selected_area = p_area; /* * We have to load all title information */ /* title number as it appears in the interface list */ p_dvd->i_title = p_area->i_id; p_dvd->i_chapter_nb = p_area->i_part_nb; if( IfoTitleSet( p_dvd->p_ifo, p_dvd->i_title ) < 0 ) { msg_Err( p_input, "fatal error in vts ifo" ); free( p_dvd ); return -1; } /* title position inside the selected vts */ i_vts_title = vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_num; p_dvd->i_title_id =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -