📄 dvd_reader.c
字号:
/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- *//* * Copyright (C) 2001, 2002, 2003 Billy Biggs <vektor@dumbterm.net>, * H錵an Hjort <d95hjort@dtek.chalmers.se>, * Bj鰎n Englund <d4bjorn@dtek.chalmers.se> * * Modified for use with MPlayer, changes contained in libdvdread_changes.diff. * detailed changelog at http://svn.mplayerhq.hu/mplayer/trunk/ * $Id: dvd_reader.c,v 1.2 2008/03/03 08:11:34 dsqiu Exp $ * * 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. */#include "config.h"#include <sys/types.h>#include <sys/stat.h>#include <sys/time.h> /* For the timing of dvdcss_title crack. */#include <fcntl.h>#include <mplaylib.h>#include <mplaylib.h>#include <errno.h>#include <mplaylib.h>#include <mplaylib.h>#include <dirent.h> #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__bsdi__) || defined(__DARWIN__) || defined(__DragonFly__)#define SYS_BSD 1#endif#if defined(__sun)#include <sys/mnttab.h>#elif defined(hpux)#include </usr/conf/h/mnttab.h>#elif defined(SYS_BSD)#include <fstab.h>#elif defined(__linux__) || defined(__CYGWIN__)#include <mntent.h>#endif#include "dvd_reader.h"#include "dvd_input.h"#include "dvd_udf.h"#include "md5.h"#include "dvdread_internal.h"#define DEFAULT_UDF_CACHE_LEVEL 0struct dvd_reader_s { /* Basic information. */ int isImageFile; /* Hack for keeping track of the css status. * 0: no css, 1: perhaps (need init of keys), 2: have done init */ int css_state; int css_title; /* Last title that we have called dvdinpute_title for. */ /* Information required for an image file. */ dvd_input_t dev; /* Information required for a directory path drive. */ char *path_root; /* Filesystem cache */ int udfcache_level; /* 0 - turned off, 1 - on */ void *udfcache; /* block aligned malloc */ void *align; /* error message verbosity level */ int verbose;};struct dvd_file_s { /* Basic information. */ dvd_reader_t *dvd; /* Hack for selecting the right css title. */ int css_title; /* Information required for an image file. */ uint32_t lb_start; uint32_t seek_pos; /* Information required for a directory path drive. */ size_t title_sizes[ 9 ]; dvd_input_t title_devs[ 9 ]; /* Calculated at open-time, size in blocks. */ ssize_t filesize;};#define DVDREAD_VERBOSE_DEFAULT 0int get_verbose(void){ char *dvdread_verbose; int verbose; dvdread_verbose = getenv("DVDREAD_VERBOSE"); if(dvdread_verbose) { verbose = (int)strtol(dvdread_verbose, NULL, 0); } else { verbose = DVDREAD_VERBOSE_DEFAULT; } return verbose;}int dvdread_verbose(dvd_reader_t *dvd){ return dvd->verbose;}dvd_reader_t *device_of_file(dvd_file_t *file){ return file->dvd;}/** * Returns the compiled version. (DVDREAD_VERSION as an int) */int DVDVersion(void){ return DVDREAD_VERSION;}/** * Set the level of caching on udf * level = 0 (no caching) * level = 1 (caching filesystem info) */int DVDUDFCacheLevel(dvd_reader_t *device, int level){ struct dvd_reader_s *dev = (struct dvd_reader_s *)device; if(level > 0) { level = 1; } else if(level < 0) { return dev->udfcache_level; } dev->udfcache_level = level; return level;}void *GetUDFCacheHandle(dvd_reader_t *device){ struct dvd_reader_s *dev = (struct dvd_reader_s *)device; return dev->udfcache;}void SetUDFCacheHandle(dvd_reader_t *device, void *cache){ struct dvd_reader_s *dev = (struct dvd_reader_s *)device; dev->udfcache = cache;}void *GetAlignHandle(dvd_reader_t *device){ struct dvd_reader_s *dev = (struct dvd_reader_s *)device; return dev->align;}void SetAlignHandle(dvd_reader_t *device, void *align){ struct dvd_reader_s *dev = (struct dvd_reader_s *)device; dev->align = align;}/* Loop over all titles and call dvdcss_title to crack the keys. */static int initAllCSSKeys( dvd_reader_t *dvd ){ struct timeval all_s, all_e; struct timeval t_s, t_e; char filename[ MAX_UDF_FILE_NAME_LEN ]; uint32_t start, len; int title; char *nokeys_str = getenv("DVDREAD_NOKEYS"); if(nokeys_str != NULL) return 0; if(dvd->verbose >= 1) { fprintf( stderr, "\n" ); fprintf( stderr, "libdvdread: Attempting to retrieve all CSS keys\n" ); fprintf( stderr, "libdvdread: This can take a _long_ time, " "please be patient\n\n" ); } gettimeofday(&all_s, NULL); for( title = 0; title < 100; title++ ) { gettimeofday( &t_s, NULL ); if( title == 0 ) { sprintf( filename, "/VIDEO_TS/VIDEO_TS.VOB" ); } else { sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 0 ); } start = UDFFindFile( dvd, filename, &len ); if( start != 0 && len != 0 ) { /* Perform CSS key cracking for this title. */ if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", filename, start ); } if( dvdinput_title( dvd->dev, (int)start ) < 0 ) { if(dvd->verbose >= 0) { fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)\n", filename, start); } } gettimeofday( &t_e, NULL ); if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Elapsed time %ld\n", (long int) t_e.tv_sec - t_s.tv_sec ); } } if( title == 0 ) continue; gettimeofday( &t_s, NULL ); sprintf( filename, "/VIDEO_TS/VTS_%02d_%d.VOB", title, 1 ); start = UDFFindFile( dvd, filename, &len ); if( start == 0 || len == 0 ) break; /* Perform CSS key cracking for this title. */ if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Get key for %s at 0x%08x\n", filename, start ); } if( dvdinput_title( dvd->dev, (int)start ) < 0 ) { if(dvd->verbose >= 0) { fprintf( stderr, "libdvdread: Error cracking CSS key for %s (0x%08x)!!\n", filename, start); } } gettimeofday( &t_e, NULL ); if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Elapsed time %ld\n", (long int) t_e.tv_sec - t_s.tv_sec ); } } title--; if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Found %d VTS's\n", title ); } gettimeofday(&all_e, NULL); if(dvd->verbose >= 1) { fprintf( stderr, "libdvdread: Elapsed time %ld\n", (long int) all_e.tv_sec - all_s.tv_sec ); } return 0;}/** * Open a DVD image or block device file. * Checks if the root directory in the udf image file can be found. * If not it assumes this isn't a valid udf image and returns NULL */static dvd_reader_t *DVDOpenImageFile( const char *location, int have_css ){ dvd_reader_t *dvd; dvd_input_t dev; int verbose; verbose = get_verbose(); dev = dvdinput_open( location ); if( !dev ) { if(verbose >= 1) { fprintf( stderr, "libdvdread: Can't open '%s' for reading: %s\n", location, strerror(errno)); } return NULL; } dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); if( !dvd ) { int tmp_errno = errno; dvdinput_close(dev); errno = tmp_errno; return NULL; } dvd->verbose = verbose; dvd->isImageFile = 1; dvd->dev = dev; dvd->path_root = NULL; dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL; dvd->udfcache = NULL; dvd->align = NULL; if( have_css ) { /* Only if DVDCSS_METHOD = title, a bit if it's disc or if * DVDCSS_METHOD = key but region missmatch. Unfortunaly we * don't have that information. */ dvd->css_state = 1; /* Need key init. */ } dvd->css_title = 0; /* sanity check, is it a valid UDF image, can we find the root dir */ if(!UDFFindFile(dvd, "/", NULL)) { dvdinput_close(dvd->dev); if(dvd->udfcache) { FreeUDFCache(dvd, dvd->udfcache); } if(dvd->align) { if(dvd->verbose >= 0) { fprintf(stderr, "libdvdread: DVDOpenImageFile(): Memory leak in align functions 1\n"); } } free(dvd); return NULL; } return dvd;}static dvd_reader_t *DVDOpenPath( const char *path_root ){ dvd_reader_t *dvd; dvd = (dvd_reader_t *) malloc( sizeof( dvd_reader_t ) ); if( !dvd ) { return NULL; } dvd->verbose = get_verbose(); dvd->isImageFile = 0; dvd->dev = 0; dvd->path_root = strdup( path_root ); if(!dvd->path_root) { free(dvd); return 0; } dvd->udfcache_level = DEFAULT_UDF_CACHE_LEVEL; dvd->udfcache = NULL; dvd->align = NULL; dvd->css_state = 0; /* Only used in the UDF path */ dvd->css_title = 0; /* Only matters in the UDF path */ return dvd;}#if defined(__sun)/* /dev/rdsk/c0t6d0s0 (link to /devices/...) /vol/dev/rdsk/c0t6d0/?? /vol/rdsk/<name> */static char *sun_block2char( const char *path ){ char *new_path; /* Must contain "/dsk/" */ if( !strstr( path, "/dsk/" ) ) return (char *) strdup( path ); /* Replace "/dsk/" with "/rdsk/" */ new_path = malloc( strlen(path) + 2 ); strcpy( new_path, path ); strcpy( strstr( new_path, "/dsk/" ), "" ); strcat( new_path, "/rdsk/" ); strcat( new_path, strstr( path, "/dsk/" ) + strlen( "/dsk/" ) ); return new_path;}#endif#if defined(SYS_BSD)/* FreeBSD /dev/(r)(a)cd0c (a is for atapi), recomended to _not_ use r update: FreeBSD and DragonFly no longer uses the prefix so don't add it. OpenBSD /dev/rcd0c, it needs to be the raw device NetBSD /dev/rcd0[d|c|..] d for x86, c (for non x86), perhaps others Darwin /dev/rdisk0, it needs to be the raw device BSD/OS /dev/sr0c (if not mounted) or /dev/rsr0c ('c' any letter will do) returns a string allocated with strdup which should be free()'d when no longer used.*/static char *bsd_block2char( const char *path ){#if defined(__FreeBSD__) || defined(__DragonFly__) return (char *) strdup( path );#else char *new_path; /* If it doesn't start with "/dev/" or does start with "/dev/r" exit */ if( strncmp( path, "/dev/", 5 ) || !strncmp( path, "/dev/r", 6 ) ) return (char *) strdup( path ); /* Replace "/dev/" with "/dev/r" */ new_path = malloc( strlen(path) + 2 ); strcpy( new_path, "/dev/r" ); strcat( new_path, path + strlen( "/dev/" ) ); return new_path;#endif /* __FreeBSD__ || __DragonFly__ */}#endifdvd_reader_t *DVDOpen( const char *path ){ struct stat fileinfo; int ret, have_css; char *dev_name = NULL; int internal_errno = 0; int verbose; if( path == NULL ) { errno = EINVAL; return NULL; } verbose = get_verbose();#ifdef WIN32 /* Stat doesn't work on devices under mingwin/cygwin. */ if( path[0] && path[1] == ':' && path[2] == '\0' ) { /* Don't try to stat the file */ fileinfo.st_mode = S_IFBLK; } else#endif { ret = stat( path, &fileinfo ); if( ret < 0 ) { int tmp_errno = errno; /* If we can't stat the file, give up */ if(verbose >= 1) { fprintf( stderr, "libdvdread: Can't stat '%s': %s\n", path, strerror(errno)); } errno = tmp_errno; return NULL; } } /* Try to open libdvdcss or fall back to standard functions */ have_css = dvdinput_setup(); /* First check if this is a block/char device or a file*/ if( S_ISBLK( fileinfo.st_mode ) || S_ISCHR( fileinfo.st_mode ) || S_ISREG( fileinfo.st_mode ) ) { /** * Block devices and regular files are assumed to be DVD-Video images. */ dvd_reader_t *dvd = NULL;#if defined(__sun) dev_name = sun_block2char( path );#elif defined(SYS_BSD) dev_name = bsd_block2char( path );#else dev_name = strdup( path );#endif dvd = DVDOpenImageFile( dev_name, have_css ); free( dev_name ); return dvd; } else if( S_ISDIR( fileinfo.st_mode ) ) { dvd_reader_t *auth_drive = 0; char *path_copy;#if defined(SYS_BSD) struct fstab* fe;#elif defined(__sun) || defined(__linux__) || defined(__CYGWIN__) FILE *mntfile;#endif /* XXX: We should scream real loud here. */ if( !(path_copy = strdup( path ) ) ) return 0;#ifndef WIN32 /* don't have fchdir, and getcwd( NULL, ... ) is strange */ /* Resolve any symlinks and get the absolut dir name. */ { char *new_path; char *current_path; current_path = malloc(PATH_MAX); if(current_path) { if(!getcwd(current_path, PATH_MAX)) { free(current_path); current_path = NULL; } } if(current_path) { chdir( path_copy ); new_path = malloc(PATH_MAX); if(new_path) { if(!getcwd(new_path, PATH_MAX )) { free(new_path); new_path = NULL; } } chdir(current_path); free(current_path); if( new_path ) { free( path_copy ); path_copy = new_path; } } }#endif /** * If we're being asked to open a directory, check if that directory * is the mountpoint for a DVD-ROM which we can use instead. */ if( strlen( path_copy ) > 1 ) { if( path_copy[ strlen( path_copy ) - 1 ] == '/' ) { path_copy[ strlen( path_copy ) - 1 ] = '\0';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -